WatchOS 1 causes issues on iOS app and making it restart

Hi all,


I have a rare issue that happens when I use the watch (OS1) and my iOS app.


Scenario:

  • iOS app is in background for a long time. Didn't went through willTerminate according to logs.
  • Watch is connecting to the iOS app when watch app is open using handleWatchKitExtensionRequest in order to receive a value stored in appDelegate.
  • In iOS app I begin a background task with beginBackgroundTaskWithName inside the handleWatch method so it will let me do a small job in the BG.
  • iOS app is calling to an ivar dictionary which is stored in appDelegate and was full with values before app went to BG (couple of hours before).
  • Somehow this ivar became nil (nothing in my code caused it according to my logs. Even added an observeValueForKeyPath to grab any change but didn't hit the observer).
  • Couple of millis after that the iOS app restarted itself (went into didFinishLaunching).


I'm trying to figure out what just happened and can't find any explanation. How come the ivar becomes nil and how come the iOS app just restarts itself?


HELP.

Accepted Reply

Well, I thought about it, but then I got scared that some inits will occur twice so I made a delay.

In my app I'm checking if my ivars are inited (they only get inited in didFinishLaunching), and if not I send a delay response to the watch with 1 sec delay.

The watch then send the same request after one sec, but before that the didFinishLaunching occur and init all ivars.

Works ok.

I reported this as a bug to Apple. Lets see whats their response.

Replies

You can't prevent an app termination.

iOS may close your app anytime.

So, what you can do is save your data in a file on willTerminate and load it on next run.

You can use NSKeyedArchiver, it's pretty simple.

Thanks PrinceCreed, but the problem is that the app was not terminated (OS wise) as I have never reached willTerminate method.

I just found another thread talking exactly on the same issue I experience:

  • App is getting killed by iOS.
  • Watchkit extension calls iOS app using openParentApplication.
  • handleWatchKitExtensionRequest is getting called BEFORE APP IS RESTARTED (hence the ivar is nil).
  • App is restarted by iOS and didFinishLaunching is getting called.


https://forums.developer.apple.com/thread/8057


Anyone experienced the same? Any idea for solution? Is this a bug or a feature?

Ah, yes!

I had the same problem. I solved creating a loadApp method.

- (void) loadApp {
    // load ivars

    hasLoaded = YES;
}


I use it in didFinishLaunchingWithOptions to normally load my ivars:

    // load application
    if (!hasLoaded) {
        [self loadApp];
    }


Then in handleWatchKitExtensionRequest I do the same:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    dispatch_async(dispatch_get_main_queue(), ^{
        // set a background task
        __block UIBackgroundTaskIdentifier backgroundTask;
        backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
            [application endBackgroundTask:backgroundTask];
            backgroundTask = UIBackgroundTaskInvalid;
            reply(nil);
        }];

        // load application
        if (!hasLoaded) {
            [self loadApp];
        }

        // do something
        reply(nil);

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 2), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // end background task
            [application endBackgroundTask:backgroundTask];
            backgroundTask = UIBackgroundTaskInvalid;
        } );
    });
}

Well, I thought about it, but then I got scared that some inits will occur twice so I made a delay.

In my app I'm checking if my ivars are inited (they only get inited in didFinishLaunching), and if not I send a delay response to the watch with 1 sec delay.

The watch then send the same request after one sec, but before that the didFinishLaunching occur and init all ivars.

Works ok.

I reported this as a bug to Apple. Lets see whats their response.