[TIMOB-25901] iOS: App crashes when background services expire and queue tries to flush
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Critical |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2018-06-22T10:41:00.000+0000 |
Affected Version/s | Release 6.3.0, Release 7.1.0 |
Fix Version/s | Release 7.5.0 |
Components | iOS |
Labels | ios |
Reporter | Igor Stojanovic |
Assignee | Hans Knöchel |
Created | 2018-03-23T20:02:05.000+0000 |
Updated | 2018-10-18T10:51:41.000+0000 |
Description
File TiApp.m
App crashes on line 632
/* for (id key in pendingCompletionHandlers) {
[self completionHandler:key withResult:2]; //UIBackgroundFetchResultFailed
} */
// elements of array are removed while array is enumerated
// YOU SHOULD TRY LIKE THIS:
for (id key in [pendingCompletionHandlers allKeys]) {
[self completionHandler:key withResult:2]; //UIBackgroundFetchResultFailed
}
Hey [~office@smartbit.rs], thanks for your report! What a stupid typo, sorry for that. We'll fix it right away and release it with the next patch. *EDIT*: Actually, I would like to propose a different change: Instead of looping through a mutable dictionary and remove keys during the iteration, I would rather mark the keys that should be called in a separate dictionary, call them and remove them from the original dictionary later. Does that make sense? I still wonder why this didn't surface before - maybe only in some cases where it's causing a race condition?
Hey Hans, AllKeys will create separated (new) Array with keys. And iteration in this case goes trough that array instead mutableDict. Your propose also could be good but it depend of object inside dict. Probably you can also remove original dictionary later but in that case for some time you will have objects inside array which can have maybe undefined state (I don't know full code...) E.g. loop completionHandler = [pendingCompletionHandlers objectForKey:key]; completionHandler(result); // this is called for each object but object is still alive when loop is ended end loop // in this point we still have objects in Dict. but we called completionHandler(result); IS THAT DANGEROUS ? [pendingCompletionHandlers removeAllObjects];
PR: https://github.com/appcelerator/titanium_mobile/pull/9957 Test-Case: Follow [this guide](https://docs.appcelerator.com/platform/latest/#!/guide/iOS_Background_Services) and let the background-service expire. [~office@smartbit.rs] If you don't mind, I'd like to ask you to test this change as well. I decided to refactor a bit more and change the handler removal to an own guard ("removeAfterExecution") that is not called anymore, since the whole dictionary is cleared after the enumeration anyway. Thanks again for bringing this up!
[~office@smartbit.rs] Have you been able to verify the changes on your end? Thanks!
Hi Hans, It looks good to me... We will schedule some time for test in to the company in next few weeks. Thanks
[~office@smartbit.rs] The PR was just merged. Let me know how your internal tests went for another opinion!
*Closing ticket.* Verified fix in SDK Version
7.5.0.v20181016071050
using the examples from https://docs.appcelerator.com/platform/latest/#!/guide/iOS_Background_Services *Test environment*