Clarification about WKWatchConnectivityRefreshBackgroundTask - watchos

In Apple's sample project SimpleWatchConnectivity there is a comment saying
WKWatchConnectivityRefreshBackgroundTask should be completed – Otherwise they will keep consuming
the background executing time and eventually causes an app crash.
The timing to complete the tasks is when the current WCSession turns to not .activated or
hasContentPending flipped to false (see completeBackgroundTasks), so KVO is set up here to observe
the changes if the two properties
My question is: Is this always the case for timing the call on completeBackgroundTasks (KVO on hasContentPending/activation)? Shouldn't I try to defer completeBackgroundTasks until I have done all the work that normally happens when I receive data over WatchConnectivity?

Related

Does setting currentTime always trigger canplay?

I can't find an exact answer online. The closest I get is a description of the canplay event.
The user agent can resume playback of the media data, but estimates that if playback were to be started now, the media resource could not be rendered at the current playback rate up to its end without having to stop for further buffering of content.
Here is my code
// fyi at this point i just loaded the video from an <input>. the currentTime is 0.
var posterFrame = 3;
var longEnough = vid.duration >= posterFrame;
vid.oncanplay = function () { getThumb.apply(self); }
vid.currentTime = longEnough ? posterFrame : 0;
It works just fine for me but I am concerned that sometimes setting currentTime won't trigger oncanplay and the whole thing will just stop.
While writing my own html5 video player, I came across this same question. Further searching lead me to this bug report:
https://bugzilla.mozilla.org/show_bug.cgi?id=773885
which suggests the behavior as a dupe to bug report 664842. While 664842 is specific to the related 'canplaythrough', there is related discussion by Mozilla devs:
The spec says: canplaythrough fires when "readyState is newly equal to HAVE_ENOUGH_DATA.".
Elsewhere it says "When the ready state of a media element whose networkState is not NETWORK_EMPTY changes, the user agent must follow the steps given below: [...] If the new ready state is HAVE_ENOUGH_DATA [...] the user agent must finally queue a task to fire a simple event named canplaythrough."
There is a followup request to make canplay & canplaythrough one time events here:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=12982
which says the behavior won't be changed.
Firefox interprets the spec as allowing canplay/canplaythrough to be fired multiple times as readyState changes allow. This interpretation is useful because canplaythrough is fired optimistically based on estimated transfer completion time. This estimate may become invalid if, for example, network conditions or the bitrate of the media changes. It is useful to signal this change in state by moving to and from HAVE_ENOUGH_DATA (and firing the related events) as conditions change.
Seeking to a new location in the media may result in a previous canplaythrough estimate becoming invalid if the seek location is in an unbuffered segment of the media that requires a new network request to transfer or significant decoding work. It then becomes more consistent (and therefore easier to code against) if these events are also fired when seeking to a range that is already buffered.
Although that discussion is from 2011, considering that the behavior seems to still be implemented, I think it's safe to say that yes, it should alway trigger it, so long as you don't pass it anything odd like null media.

How to properly execute performFetchWithCompletionHandler with multiple blocks inside

I'm using the background fetch method performFetchWithCompletionHandler in order to update some user data. However, those processes are fairly complicated and include block statements, so they don't execute synchronously.
My concern is that I am always returning completionHandler(UIBackgroundFetchResultNewData);
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Start background data fetch");
// Update data -- this method contains various blocks inside
[GETDataRequest updateUserDataWithUser: user];
// Update images -- this method contains various blocks inside
[GETImagesRequest updateUserImagesWithUser: user];
NSLog(#"Background Data Fetch completed");
completionHandler(UIBackgroundFetchResultNewData);
}
According to this post, in regards to completionHandler(UIBackgroundFetchResultNewData) the following was mentioned:
You have to call this to let iOS know what the result of your background fetch was. It uses this information to schedule future background fetches. If you neglect to do this, future background fetches may be delayed by the OS. The consequences of not calling this handler might include terminating your app altogether.
As you can see here, I am always saying it's successful whether or not it actually is. The answerer had this to say about my situation:
...you should call the completion handler only when your fetch is actually complete. Otherwise iOS will probably put your application back to sleep before the connection completes, and apps shouldn't actually be able to determine UIBackgroundFetchResultNewData versus UIBackgroundFetchResultNoData or UIBackgroundFetchResultFailed until then anyway. How do you know your connection will succeed?
Is what I'm doing ACTUALLY a problem? Will it actually cut off the updates? If it is going to produce unexpected results, what's the solution to this mess? The answer to the question I mentioned wasn't clear enough to me. I have tried using block variables to make it function as it should, but have been unsuccessful. Much appreciated.
The code you are using is meant for Background Fetch Refresh functionality, through this you can make a quick refresh to your app when its in background by mentioning the system time interval to minimum. This service is available in the delegate method performFetchWithCompletionHandler and it will last for 30 seconds. You need to manage your code accordingly to get updated result and then at end as per your result you need to call the appropriate completion handler block.
If you have the long running background task I will prefer then to use Background Fetch Services using NSURLSessions.

iOS - wait till a process ends

This is an IOS6 question.
I have an app that is calling a class (A) to check something. Then I want to call a class (B) to do something else
Is it possible to make sure process B doesn't start before process A finishes?
At the moment, I just call one after the other in the RootVC.
Each is showing a modal view, and I only get to see B ..
[self performA];
[self performB];
Thanks
There are several tools for managing the order of execution of parts of your application available to you. However since you are presenting view controllers you have a couple of constraints; you don't want to block the main thread (or else the app will become unresponsive) and you must perform UI actions on the main thread.
In this case the most common, and probably most appropriate, solution is to setup a callback to trigger action B when action A finishes.
The modal view controller presented as part of A might call a delegate when it has finished its task successfully. That delegate can then begin task B.
Alternately you might pass a block to A which A will execute when it finishes. That block can then perform task B.
I took the dare and failed.
The story: My app has been giving me hell updating from an iOS4 target to iOS6 (with a contingent sub of code for iOS5/3GS). It crashes unless i use #try etc... with a built in delay interval on the reattempt (which is stupid, 'cause I don't know how large a database the users have, nor how long it will take to load them). It's a painful way to get around my real problem: the view loads before the CoreData stack (logs) can be loaded completely and I don't see a way to make the initial view wait until its NSMutableArray (based on the CoreData database of my object) loads. Basically, I keep getting a false error about addObjectsSortedBy: the foremost attribute of my entity.
Threading does seem to be the answer, but I need to load an NSMutableArray and feed it into my initialViewController, which will be visible on every launch (excluding FirstTime initial), but my attempt (okay, 12 attempts) to use threading just made the crash occur earlier in the app launch.
The result: I bow down to those who have wrangled that bull of threads.
My solution has been to build in a notification in the AppDelegate.m, my initialViewController viewDidLoad is told to listen for it before anything else. If it gets the notification it skips ahead and completes the normal process unto [super viewDidLoad]; if not, it executes #try, #catch, #finally. In the #try I attempt to proceed as though the notification arrived (like it was a little late), then I handle (#catch) the error by displaying a "Please Wait" label to the user, then I tell the app to wait .xx and repeat the original addObjectsSortedBy: command as though everything were kösher to begin with.The sweet-spot for my app, with images and data in the logs appears to be .15 for the wait interval #50 test entries, with time to spare and no obvious lag on load. I could probably go down to .10 #50 entries.
BUT: I don't know how to scale this, without having the logs loaded enough to get an object.count! Without that, there is no way to scale my delay, which means it may (read:will) not work for large logs with many entries (200+)!
I have a work-around, but I'm going to keep trying to get a grip on threading, in order to have a solution. And to be honest, once I hit 20 entries, the notification never hits in time for the #try to occur.
If you can, use threads. I painted myself into a corner by failing to do so early on and am paying for it: my app has been in need of an overhaul, but I need this notch in my belt before it will be worthwhile. The earlier you can implement threaded loading the better for your long-term development. In the meantime, you may be able to use my work-around to continue testing other parts of your app.

Timing and repeating thread execution in Objective-C

I'm wondering if I'm able to time a thread to be executed repeatedly (like when using the scheduledTimerWithTimeInterval method in NSTimer).. I have a view controller, where there is a method I want it to be executed either manually (by clicking a button), or automatically (by timing the method execution). The problem is that, this method will connect with a remote server, and it will update the result on the view, so I don't want it to block the main thread (the view controller thread).
I don't know what to use, so if there's anyone knows how, please let me know :)
Thanks in advance..
It sounds like you might be using an NSURLConnection, and if that's the case, then as joshpaul noted, it will act asynchronously by default. That is to say, when you start the connection, the NSURLConnection object will create a new thread, do its work on that thread, and return results to you on the original thread via the delegate methods, cleaning up the second thread afterwards. This means that the original thread, main or not, will not be blocked while the connection does its work. All you have to do, then, is have your timer's action create and run the connection.
In other cases, you have a couple of options. It's easy enough to set up a timer method that will call another method to be performed in the background:
- (void)periodicMethodTimerFire:(NSTimer *)tim {
[self performSelectorInBackground:#selector(myPeriodicMethod:)
withObject:myPeriodicArgument];
}
This can make it difficult to get results back from the other thread (because you need to pass a reference to the original thread to the method). However, since you seem to be on the main thread to begin with, you can use performSelectorOnMainThread:withObject:waitUntilDone: passing NO for the wait argument to get back.
The more complicated option is to set up your own background thread with a timer running on it, but I'd be surprised if that was really necessary.
If you're using NSURLConnection, it's asynchronous. That'll likely work for your needs.

problem with asynchronous programming while calling 2 methods in Objective-C

Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = [classB_Obj authenticateMobileUser];
}
Inside ClassB:
-(AuthenticateObj*)authenticateMobileUser
{
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
return authenticate_G_Obj;
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
}
Now once the authenticateMobileUser method of classB returns the controll back to ClassA, we will get the Object authenticate_Obj initiated.
My problem is , when i run the project the authenticate_Obj is NULL... actually when it enters the handler method , the Object is initiallized. but the controlled is returned back to ClassA, without entering into Handler method. I guess this is the problem of Asynchronous execution.
How to make it enter into handler method and then only return the controll to ClassA??
Plz help me..
Thank You.
It sounds like what you think you want to do is to block execution until authentication completes. This might be possible if AuthenticateMobileServer spawns a background thread to work in -- you'd use a synchronisation object such as NSLock -- but it's really a Bad Idea. Why have a background thread at all if you're going to block anyway? And thread synchronisation is notoriously tricky and prone to errors if you don't know what you're doing, which (let's face it) you don't.
Instead, you probably should accept that there will be a period of uncertainty while the authentication takes place, during which your app should keep processing in some intermediate state, and then use a callback to notify you when the authentication is complete and you can then go on with whatever it is you need to do with the authenticated user.
There are a bunch of ways you could do this, and there's not enough detail in the question to say exactly which would be best. But you already seem to be using something very similar within ClassB, so I'd say do the same from ClassA:
Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = nil;
[classB_Obj authenticateMobileUserAndNotify:self action:#selector(authenticatedObject:)];
// returns more or less immediately, not yet authenticated
}
-(void)authenticatedObject:(YourAuthObjectClass*) authObj
{
authenticate_Obj = authObj;
// do post-authentication stuff here
}
Inside ClassB:
-(void)authenticateMobileUserAndNotify:(id)target action:(SEL)sel
{
// I'm making these ivars for simplicity, there might be other considerations though
callbackTarget = target;
callbackSelector = sel;
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
[callbackTarget performSelectorOnMainThread:callbackSelector withObject:authenticate_G_Obj waitUntilDone:NO];
}
Obviously this is just a sketch and not intended to be used as is. And you'll need to consider what goes on in your app while in the waiting state, with authentication in progress but authenticate_Obj still nil. But hopefully you get the idea.
I think you are saying that AuthenticateMobileServer:action: is asynchronous and you want to block until it's finished so you can get the return value. Unfortunately, we can't really tell you without knowing how it works. The main question is does it run the Handler action on the main thread or a secondary thread.
If it runs the action on the main thread, the best strategy is to return immediately from authenticateMobileUser without waiting for the authentication object and disable the UI elements that depend on being authenticated. Then later when you get the authentication object, you should re-enable the UI elements.
If it runs the action on a background thread, the easiest thing is to set up another method similar to Handler (by the way, the naming convention for methods and variables is to start with lower case), which you then invoke from Handler with performSelectorOnMainThread:waitUntilDone:. You can then use the same strategy as outlined above.
Both answers of JeremyP and walkytalky are correct and go at the heart of creating a respondsive UI. The rule of thumb:
If you doing potentially blocking operations such as networking on the main thread, you will get in trouble.
There are at least two reasons:
you are blocking the run loop so it cannot process user events anymore. This will result in a spinning beachball on the mac and a unresponsive UI on both mac and iOS.
If you are on iOS, there is a watchdog going around and checking if your UI is still responding to user events. If you are blocking the UI longer than I think 20s you will be terminated with the error code 0x8badf00d.
So to get this things done which maybe take some time you have to do it on the background thread. As the two answers of JeremyP and walkytalky point out often you get a callback. That is fine but there are in total three ways of messaging:
Delegation
Notifications
Kev-value-observing
All three can be and are used. There are subtle differences between them. One of the most important is that delegation is a 1:1 messaging whereas the other to are a 1:n messaging.
Now that said do not think that you have to use NSThread. Have a look at NSOperation and NSOperationQueue instead. They allow to encapsulate pieces of work in an operation and let them run on a queue in the background. Also if you are using these callbacks with the #selector(methodname:) syntax there is something new: blocks. Often there are equivalent methods which take a block instead of a selector to be executed as a callback.
To finish here is the golden rule:
You may update your model on the background thread, but NEVER update your UI on a background thread.
Check out the WWDC10 videos about these topics. There is a great 2-part talk about networking which explains the concepts in detail.