Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-25901] iOS: App crashes when background services expire and queue tries to flush

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2018-06-22T10:41:00.000+0000
Affected Version/sRelease 6.3.0, Release 7.1.0
Fix Version/sRelease 7.5.0
ComponentsiOS
Labelsios
ReporterIgor Stojanovic
AssigneeHans Knöchel
Created2018-03-23T20:02:05.000+0000
Updated2018-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 }

Comments

  1. Hans Knöchel 2018-03-24

    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?
  2. Igor Stojanovic 2018-03-24

    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];
  3. Hans Knöchel 2018-03-24

    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!
  4. Hans Knöchel 2018-04-09

    [~office@smartbit.rs] Have you been able to verify the changes on your end? Thanks!
  5. Igor Stojanovic 2018-04-09

    Hi Hans, It looks good to me... We will schedule some time for test in to the company in next few weeks. Thanks
  6. Hans Knöchel 2018-06-22

    [~office@smartbit.rs] The PR was just merged. Let me know how your internal tests went for another opinion!
  7. Samir Mohammed 2018-10-18

    *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*
       APPC Studio: 5.1.0.201808080937
       iPhone 6 Sim (iOS 12)
       APPC CLI: 7.0.6
       Operating System Name: Mac OS Mojave
       Operating System Version: 10.14
       Node.js Version: 8.9.1
       Xcode 10.0
       

JSON Source