nothirst / TICoreDataSync

Automatic synchronization for Core Data apps, between any combination of Mac OS X and iOS: Mac to iPhone to iPad to iPod touch and back again.
https://github.com/nothirst/TICoreDataSync/wiki
807 stars 61 forks source link

Allowing for Continued Operation Processing After App Enters Background State #41

Closed ChronicStim closed 11 years ago

ChronicStim commented 11 years ago

I'm going to submit a pull request for a possible approach to deal with this issue. Michael, it's similar to your suggestion, but I think assigning the task id at the point that the app is backgrounding is too late. Your code seems to wait for the backgrounding to happen and then you create a task to synchronize in the background. That's fine, and maybe even a good time to run a sync, but not my main concern.

I'm more concerned with the operations that are already running when the app is interrupted. Let's say we are in the middle of a whole store download or a synchronization process is already processing. In the current code, those operations will be killed after the 5 sec time limit when the app goes into the background state. There is also no clean way to cancel those ops that I could see (other than the "cancelSynchronization" method).

So, our approach was to add 2 properties to each of the sync managers and the generic operation class. One property is a BOOL flag that indicates whether or not the manager or operation is allowed to continue processing in the background. The value of this property is set by a delegate call during configuration of the manager or operation. This can give the flexibility of allowing only certain types of operations to process in the background state.

The second property is the assigned backgroundTaskID for the operation. Regardless of the value of the first flag, we still always set the backgroundTaskID to ensure that the operation is not immediately killed when the app enters the background state. We want to be able to have enough time to review it and either let it continue or cancel it.

When the appDelegate signals that the app is moving to the background state, our singleton that manages the TICDS system makes a call to the DocumentSyncManager to cancelNonBackgroundStateOperations. This causes the DSM to go through each operation in its three queues and check the shouldContinueProcessingInBackgroundState flag. If it is NO, then the op receives a cancel request. If it is YES, it is allowed to continue processing. We also call the same method on the App Sync Manager which reviews the ops in it's two operation queues.

MrRooni commented 11 years ago

In the endBackgroundTask method you're accessing the _backgroundTaskID ivar directly instead of going through the property accessor. Was there a specific reason for that?

MrRooni commented 11 years ago

I reworked the logic for that method a little bit. You may want to pull those changes down.

MrRooni commented 11 years ago

Also, just so I'm understanding it properly, with your enhancements I shouldn't need to worry about firing off that high level background task request from my app delegate if I've set my application and document sync managers to allow background operations, correct?

ChronicStim commented 11 years ago

Exactly. Your operations will already have requested and received a background task id, so there is no need to request one when the state changes. What you will want to do from the app delegate is kick off the call to cancelNonBackgroundStateOperations in both sync managers so that it can nicely cancel any tasks that you don't want to run in the background.

There is no doubt some overhead associated with getting the background task ids for every operation, even when most will never be asked to run in the background, but I don't believe it is significant (although I have not tested this at all). And, I don't know of any other way to prepare an operation to deal with a move to the background state without doing something like this.

ChronicStim commented 11 years ago

checking the ivar value directly in that IF statement is just habit. Feel free to change it if you think it is better or more consistent with the framework using the accessor.