So - after a lot of playing - I figured out a way to make it work, yet I have one thing that I didn't figure out how to bypass (and drives me crazy..).
I have an app for the watch that needs data from GooglePlaces (no interface for iOS yet...). So - I use WCSession, and use the phone, using sendMessage
, to query GooglePlaces through the phone, returning the nearby places to the watch.
To begin, it appears GooglePlaces currentPlace
function is called on the same thread it is being called to (by queueing it for later) -- a problem since it is scheduled to when after the program is closed (since the function didReceiveMessage
exits before it is called). So instead of running it on the main queue, I start a thread and run this code on it....
An issue with it is that replyHandler
must be called before session:didReceiveMessage
is finishing execution (otherwise the process is killed if the app is in background mode).
So the code I built to bypass this issue looks like that (Note I have a nested cloudKit code in there.. ):
let queue = OperationQueue();
var finishedRunning = false;
queue.addOperation{
sleep(1);
self.placesClient?.currentPlace(callback: {
(placeLikelihoodList: GMSPlaceLikelihoodList?, error: Error?) -> () in
if let err = error {
retVal.removeAll();
retVal["error"] = err.localizedDescription;
finishedRunning = true;
return;
}
let predicate = NSPredicate(format: "selected = 1");
let query = CKQuery(recordType: "someInfo", predicate: predicate);
let privDb = CKContainer.default().privateCloudDatabase;
privDb.perform(query, inZoneWith: nil, completionHandler: {records, error in
if let err = error {
retVal.removeAll();
retVal["error"] = err.localizedDescription;
finishedRunning = true;
return;
}
retVal["completed"] = 1;
finishedRunning = true;
});
});
}
while !finishedRunning{
sleep(1);
}
marker = true;
replyHandler(retVal);
Those who read the code carefully noticed I added a sleep(1);
command up there... immediately after beginning the queue.
It is unclear for me why, but without this sleep call, the GooglePlaces callback is not called!!
I would really like to remove this specific call.. Does anybody have an idea why it happens? How to bypass it?
(P.S. I am not sure if locks are necessary to protect finishedRunning
.. since it works, I assume none are necessary).
P.S. #2 - I know it is "dirty", but there is no other way to bypass that ... since I want this data on the watch, I gave up on elegancy...
Thanks!!
The problem appeared to be different than what I expected...
It appears the NSUserDefaults
is not "waiting" for itself to be loaded before giving access to its content:
In my code, I read a config before it.
The code for that was:
let config :UserDefaults = UserDefaults();
// read config
Had to change to:
let config :UserDefaults = UserDefaults();
config.synchronize();
// read config
This is because without the synchronize, the watch code ran faster than the asynchronous loading of the config... which lead to a nil
returned from a config that I expected having...
This resulted in the code dying, and killing the whole session..
The one second delay allowed the asynchronous process to complete loading, and return the expected value...