Of my iBeacon's three minors, I am only able to range one of them. How can I range all three? - ibeacon

My iBeacon is set up to select between three minor values using a switch. The switch sets the value of the iBeacon minor. So only one minor is transmitting at any given time. But I can only reliably range the iBeacon with the "00" minor. I would like to range any one of the three, depending on where the selection switch is set.
Here is my code:
class LifeGardViewController: UIViewController, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
var detectorID:UInt16? = 10//major for all three minors
var safeBeaconRegion: CLBeaconRegion?
var lowBatteryBeaconRegion: CLBeaconRegion?
var gasolineVaporBeaconRegion: CLBeaconRegion?
var safeBeaconConstraint: CLBeaconIdentityConstraint?
var lowBatteryBeaconConstraint: CLBeaconIdentityConstraint?
var gasolineVaporBeaconConstraint: CLBeaconIdentityConstraint?
var lifeGardBeaconUUID = UUID(uuidString: "6B4BCFCE-174E-4BAC-A814-092E77F6B700")!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestWhenInUseAuthorization()
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedWhenInUse:
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self){
if CLLocationManager.isRangingAvailable(){
buildBeaconRegionsAndConstraints()
} else {
//device is not compaitble, uninstall app
}
}
case .notDetermined, .denied, .restricted:
break
default:
break
}
}
func buildBeaconRegionsAndConstraints() {
safeBeaconRegion = CLBeaconRegion(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 00, identifier: "Life-Gard Safe Beacon")
safeBeaconConstraint = CLBeaconIdentityConstraint(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 00)
lowBatteryBeaconRegion = CLBeaconRegion(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 01, identifier: "Life-Gard Low Battery Beacon")
lowBatteryBeaconConstraint = CLBeaconIdentityConstraint(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 01)
gasolineVaporBeaconRegion = CLBeaconRegion(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 02, identifier: "Life-Gard Gasoline Vapor Beacon")
gasolineVaporBeaconConstraint = CLBeaconIdentityConstraint(uuid: lifeGardBeaconUUID, major: detectorID!, minor: 02)
startMonitoring()
}
func startMonitoring(){
locationManager?.startMonitoring(for: safeBeaconRegion!)
locationManager?.startMonitoring(for: lowBatteryBeaconRegion!)
locationManager?.startMonitoring(for: gasolineVaporBeaconRegion!)
startRanging()
}
func startRanging(){
locationManager?.startRangingBeacons(satisfying: safeBeaconConstraint!)
locationManager?.startRangingBeacons(satisfying: lowBatteryBeaconConstraint!)
locationManager?.startRangingBeacons(satisfying: gasolineVaporBeaconConstraint!)
}
func locationManager(_ manager: CLLocationManager, didRange beacons: [CLBeacon], satisfying beaconConstraint: CLBeaconIdentityConstraint) {
print(beacons)
}
}
Even if I comment out the lines to construct the beacon region and identity constraint for minor "00" neither of the other two minors gets ranged. This is true even if I remove the app from my phone first.
Looking forward to any ideas to try.
`

The code shown in the question is correct. If you run that code and a beacon is advertising 6B4BCFCE-174E-4BAC-A814-092E77F6B700 10 1 or 6B4BCFCE-174E-4BAC-A814-092E77F6B700 10 2 then iOS is supposed to give a callback to func locationManager(_ manager: CLLocationManager, didRange beacons: [CLBeacon], satisfying beaconConstraint: CLBeaconIdentityConstraint) once per second with a count of the detected beacons. If there is no detection of that beacon, the count should be zero.
Two possibilities:
Your device is not advertising the beacon identifier you think it is. The easiest way to troubleshoot this is to get a second phone and use a beacon detector/transmitter app like my Locate Beacon for iOS, or Beacon Scope for Android.
Your iPhone is misbehaving somehow. There were isolated reports that some iOS 13 devices failed to range multiple CLBeaconIdentityConstraint instances, and using the deprecated startRangingBeacons(region: CLBeaconRegion) method resolved the issue. If you might try this deprecated method to see if it makes any difference. If you do so, be sure to change your delegate method to the equivalent deprecated version.

Related

How to use SetDisplayConfig (windows-rs) to force screen re-detection?

I am using windows-rs (Latest version from GitHub, because it contains some fixes the stable version on Crates.io doesn't have).
My goal is to develop a small software that automatically forces the screen to be re-detected and set to the highest resolution (It's for a school with a weird setup where teachers have to turn projectors on before the PC for resolutions to get detected, but often forget that, leading the PCs to have a very low resolution, and the higher resolutions not being detected).
For re-initializing the screen, I have the following function:
// Some imports may be unused here, I haven't checked them yet, the full file has more functions
use windows::Win32::Graphics::Gdi::{ChangeDisplaySettingsA, EnumDisplaySettingsA, DEVMODEA, SDC_FORCE_MODE_ENUMERATION, SDC_APPLY, SDC_SAVE_TO_DATABASE, SDC_USE_SUPPLIED_DISPLAY_CONFIG, QDC_ALL_PATHS};
use windows::Win32::Media::Audio::Endpoints::IAudioEndpointVolume;
use windows::Win32::Media::Audio::{IMMDeviceEnumerator, MMDeviceEnumerator};
use windows::Win32::Devices::Display::{GetDisplayConfigBufferSizes, QueryDisplayConfig, SetDisplayConfig, DISPLAYCONFIG_TOPOLOGY_ID};
use windows::core::GUID;
use windows::Win32::System::Com::{CoInitialize, CoCreateInstance, CLSCTX_ALL};
// Forces Windows to reinit display settings
pub fn force_reinit_screen() -> i32 {
let mut path_count = 0;
let mut mode_count = 0;
let result = unsafe { GetDisplayConfigBufferSizes(QDC_ALL_PATHS, &mut path_count, &mut mode_count) };
println!("GetDisplayConfigBufferSizes returned {}", result);
let mut path_array = Vec::with_capacity(path_count as usize);
let mut mode_array = Vec::with_capacity(mode_count as usize);
let result = unsafe {
QueryDisplayConfig(
QDC_ALL_PATHS,
&mut path_count,
path_array.as_mut_ptr(),
&mut mode_count,
mode_array.as_mut_ptr(),
::core::mem::transmute(::core::ptr::null::<DISPLAYCONFIG_TOPOLOGY_ID>()),
)
};
println!("QueryDisplayConfig returned {}", result);
let flags = SDC_FORCE_MODE_ENUMERATION | SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_SAVE_TO_DATABASE;
let result = unsafe { SetDisplayConfig(Some(&path_array), Some(&mode_array), flags) };
result
}
However, it does not work on any computer I've tried this on (Returns code 87, which seems to mean bad parameters). What am I doing wrong?

Using custom class in XPC protocol

I’m attempting to write an XPC service using my own type on the withReply signature. The type/class has Xcode’s “target membership” of both the main app and the XPC service. However I am getting incompatible reply block signature in the debug output even though the same class is being used in the withReply signature however the Xcode target differs as I will explain below.
Note: This is being done in Swift using this project to get me started. Except there they use NSData instead of a custom type.
Details
For the purposes of this question I’ll use the following as an example
Custom class - Tweet - This class conforms to the NSSecureCoding protocol so that it can be passed between the main app and the XPC service
XPC Protocol - TweetTransfer with one method required func take(_ count: Int, withReply: ((Tweet) -> Void))
and then all the usual XPC boilerplate where I export an object conforming to TweetTransfer. The XPC service appears to launch but then transfer between it and the main app fails with
XPCWorker[11069:402719] <NSXPCConnection: 0x61800010e220> connection from pid 11066 received an undecodable message
The full message is below[1] but the only difference between the “wire” and “local” is that argument one is
wire - _TtC17MainApp5Tweet
local - _TtC23XPCWorker5Tweet
Where the Xcode target is different. Is that enough to throw it off? How then do I share code between an app and it's XPC service?
[1] Full error text
<NSXPCConnection: 0x61800010e220> connection from pid 11066 received an undecodable message (incompatible reply block signature (wire: <NSMethodSignature: 0x618000074ec0>
number of arguments = 2
frame size = 224
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v) 'v'
flags {}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset = 0, size = 0}
argument 0: -------- -------- -------- --------
type encoding (#) '#?'
flags {isObject, isBlock}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
argument 1: -------- -------- -------- --------
type encoding (#) '#"_TtC17MainApp5Tweet"'
flags {isObject}
modifiers {}
frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
class '_TtC17MainApp5Tweet'
vs local: <NSMethodSignature: 0x610000074740>
number of arguments = 2
frame size = 224
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v) 'v'
flags {}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset = 0, size = 0}
argument 0: -------- -------- -------- --------
type encoding (#) '#?'
flags {isObject, isBlock}
modifiers {}
frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
argument 1: -------- -------- -------- --------
type encoding (#) '#"_TtC23XPCWorker5Tweet"'
flags {isObject}
modifiers {}
frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
memory {offset = 0, size = 8}
class '_TtC23XPCWorker5Tweet'
)
Update
Some more info regarding the protocol, remoteObjectProxy connection and Tweet object. This is the protocol used for the XPC calls:
#objc(TweetTransfer)
protocol TweetTransfer {
func take(_ count: Int, withReply: replyType)
}
typealias replyType = ((Tweet) -> Void)
I'm using a type alias for convenience. And then the Tweet object is very simple and just for testing (although somewhat complicated by supporting NSSecureCoding):
final class Tweet: NSObject, NSSecureCoding {
var name: String
var text: String
static var supportsSecureCoding = true
init(name: String, text: String) {
self.name = name
self.text = text
}
init?(coder aDecoder: NSCoder) {
guard let name = aDecoder.decodeObject(forKey: "name") as? String else {
fatalError("Could not deserialise name!")
}
guard let text = aDecoder.decodeObject(forKey: "text") as? String else {
fatalError("Could not deseralise text!")
}
self.name = name
self.text = text
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(text, forKey: "text")
}
}
and finally the point at which we call the remoteObjectProxy
guard let loader = workerConnection.remoteObjectProxyWithErrorHandler(handler) as? TweetTransfer else {
fatalError("Could not map worker to TweetTransfer protocol!")
}
var tweets = [Tweet]()
loader.take(1) { tweet in
tweets.append(tweet)
}
The full message is below but the only difference between the “wire” and “local” is that argument one is
wire - _TtC17MainApp5Tweet
local - _TtC23XPCWorker5Tweet
Where the Xcode target is different. Is that enough to throw it off? How then do I share code between an app and it's XPC service?
That is indeed enough to throw it off. Swift's namespacing makes the archived object appear as a different class. You can disable name spacing by declaring your Tweet object with;
#objc(Tweet) class Tweet: NSObject, NSSecureCoding { ... }
The name in #objc(name) is often presented as a way to present a different name in objc vs Swift, but it also has the effect of disabling Swift's name spacing.
From Using Swift with Cocoa and Objective-C
When you use the #objc(name) attribute on a Swift class, the class is made available in Objective-C without any namespacing. As a result, this attribute can also be useful when migrating an archivable Objective-C class to Swift. Because archived objects store the name of their class in the archive, you should use the #objc(name) attribute to specify the same name as your Objective-C class so that older archives can be unarchived by your new Swift class.
Another alternative is to move your custom object to a Framework. That framework target then becomes the namespace, and both the XPC and App would refer to the same namespace/class in the framework.

How to identify memory leak with slowly eating up memory

I wrote a small app which calls every few seconds for checking folders. I run this app for appr. one week. Now I saw that it had occupied 32 GB of my physical 8 GB RAM. So system forced me to stop it.
So it seems that very slowly the app eats up memory. I tried Instruments. With activity monitor the only slowly growing process is "DTServiceHub". Is this something I have to watch at?
For debugging I write some information with print to standard output. Is this information dropped, because app is Cocoa app or stored somewhere till termination of the app? In this case I have to remove all these print-Statements.
Some code for looping:
func startUpdating() {
running = true
timeInterval = 5
run.isEnabled = false
setTimer()
}
func setTimer() {
timer = Timer(timeInterval: timeInterval, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: false)
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
}
func update() {
writeLOG("update -Start-", level: 0x2)
...
setTimer()
}
There are several problems with your code. You should not create a Timer and then add it to a run loop every time you set it, because the run loop will retain that Timer and will never release it. Even worse is when you try to do that every time you update. Just create the timer once. If you don't need it anymore you have to invalidate it to remove it from the run loop and allow its release. If you need to adjust it just set the next fire date.
Here is an example that was tested in a playground:
import Cocoa
class MyTimer
{
var fireTime = 10.0
var timer:Timer
init()
{
self.timer = Timer.scheduledTimer(timeInterval: fireTime, target: self, selector: #selector(update), userInfo: nil, repeats: true)
}
deinit
{
// it will remove the timer from the run loop and it will enable its release
timer.invalidate()
}
#objc func update()
{
print("update")
let calendar = Calendar.current
let date = Date()
if let nextFireDate = calendar.date(byAdding: .second, value: Int(fireTime), to: date)
{
print(date)
timer.fireDate = nextFireDate
}
}
}
let timer = MyTimer()
CFRunLoopRun()
The problem is that your app loops forever and thus never drains the auto release pool. You should never write an app like that. If you need to check something periodically, use an NSTimer. If you need to hear about changes in a folder, use NSWorkspace or kqueue or similar. In other words, use callbacks. Never just loop.

Differences between Playground and Project

In the course of answering another question, I came across a weird bug in Playground. I have the following code to test if an object is an Array, Dictionary or a Set:
import Foundation
func isCollectionType(value : AnyObject) -> Bool {
let object = value as! NSObject
return object.isKindOfClass(NSArray)
|| object.isKindOfClass(NSDictionary)
|| object.isKindOfClass(NSSet)
}
var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt = 42
var aString = "Hello world"
println(isCollectionType(arrayOfInt)) // true
println(isCollectionType(dictionary)) // true
println(isCollectionType(anInt)) // false
println(isCollectionType(aString)) // false
The code worked as expected when I put it into a Swift project or running it from the command line. However Playground wouldn't compile and give me the following error on the downcast to NSObject:
Playground execution failed: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8).
* thread #1: tid = 0x298023, 0x00007fb1d0f77fe8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8)
* frame #0: 0x00007fb1d0f77fe8
frame #1: 0x000000010ba46e12 libswiftCore.dylib`Swift._EmptyArrayStorage._withVerbatimBridgedUnsafeBuffer (Swift._EmptyArrayStorage)<A>((Swift.UnsafeBufferPointer<Swift.AnyObject>) -> A) -> Swift.Optional<A> + 50
The build platform was OS X in all three cases. Does anyone know how to get Playground to play along?
Xcode 6.3.2. Swift 1.2. OS X 10.10.3 Yosemite
Not really the cause of that bug (it does look weird) but...
You will need to use optional chaining since value can be AnyObject:
import Foundation
func isCollectionType(value : AnyObject) -> Bool {
if let object = value as? NSObject {
return object.isKindOfClass(NSArray)
|| object.isKindOfClass(NSDictionary)
|| object.isKindOfClass(NSSet)
}
return false
}
var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt = 42
var aString = "Hello world"
isCollectionType(arrayOfInt)
isCollectionType(dictionary)
isCollectionType(anInt)
isCollectionType(aString)
Also worth noting, NSArray and Array are different things:
NSArray is an immutable class:
#interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
whilst Array is a struct:
struct Array<T> : MutableCollectionType, Sliceable, _DestructorSafeContainer
With this in mind it might be surprising that isCollectionType(arrayOfInt) returns true - but there is a conversion happening.

Why is it slow to update a class property compared to a local on in Swift?

Consider the following UIViewController implementation:
class ViewController: UIViewController {
var foo:String[] = ["A","b","c"];
override func viewDidLoad() {
super.viewDidLoad()
for (var i=0; i < 1000; i++) {
foo += "bar";
}
}
}
This loop takes around 34 seconds to complete, consumes 100% CPU and uses up 54MB RAM.
If I move the foo declaration into viewDidLoad we get near instant results.
My question: What is causing this?
In the Playground I've tried the following:
Changed Environment to iOS
Built one function that just calls super.viewDidLoad() and another which does the additional array concatenation
It takes approx. 7secs for just calling the super-method and additional 3secs (10secs) with the array-stuff. For me 3 seconds for just 1000 operations seems like there must be any additional Debug-Options enabled. So, according to #nschum, try to make a release build.
Here is my code:
import UIKit
class ViewController: UIViewController
{
var foo:String[] = ["A","b","c"];
func viewDidLoadWithout() {
super.viewDidLoad()
}
func viewDidLoadWith() {
super.viewDidLoad()
for (var i=0; i < 1000; i++) {
foo += "bar";
}
}
}
var time: Int = Int(NSDate.timeIntervalSinceReferenceDate())
var cntrl = ViewController()
cntrl.viewDidLoadWithout()
time -= Int(NSDate.timeIntervalSinceReferenceDate())
time *= (-1) // 7secs
time = Int(NSDate.timeIntervalSinceReferenceDate())
cntrl = ViewController()
cntrl.viewDidLoadWith()
time -= Int(NSDate.timeIntervalSinceReferenceDate())
time *= (-1) // 10secs
Just guessing here.
In the former case you have a property of an objc class and the value is in fact an NSString. At each update of the property not only you have a dynamic dispatch call to update the property, but also another to compute the new string. Each time there is a check for the possibility that there's some Objective C observer that needs notifying. And each intermediate value is allocated on the heap. All the strings also gets eventually released and deallocated.
In the latter case it's a stack value of type String (not an NSString). And there's no one that can see it but this code. The compiler could in fact even pre-compute the size of the final result and allocate it just once, then just do a quick loop to fill it.
Not saying this is exactly what happens. I'm guessing. But the two things are certainly different.
34 seconds however is a lot. There must be something else too.

Resources