1
votes

I'm trying to call removeObserver() when the app quits. But when I used NSLog() to check, I found neither viewWillDisappear() nor viewDidDisappear() was called after the app quit in iOS simulator. I'm using a single view template, not navigation controller in similar questions.

Here is the source code:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"viewDidLoad() called");
    // Do any additional setup after loading the view, typically from a nib.

    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
        for (int i = 0; i < 4; i++) {
            UITextField *theField = self.lineFields[i];
            theField.text = array[i];
        }
    }

    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillResignActive:)
                                                 name:UIApplicationWillResignActiveNotification
                                               object:app];

}

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"viewWillDisappear() called");
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSString *)dataFilePath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = paths[0];
    return [documentDirectory stringByAppendingPathComponent:@"data.plist"];
}

- (void)applicationWillResignActive:(NSNotification *)notification {
    NSString *filePath = [self dataFilePath];
    NSArray *array = [self.lineFields valueForKey:@"text"];
    [array writeToFile:filePath atomically:YES];
}

@end
5
Are you closing or killing the app? - Pablo A.
I have tried two ways: 1. I double-click the home button and close the app; 2. I quit the iOS simulator directly. In both circumstances non of the methods is called. - Zhu Shengqi
use applicationWillTerminate: in app delegate. - aBilal17
what is deployment target? because if it is less then 7.0 then applicationWillTerminate not called when you terminate the application. - Chirag Shah
@aBilal17 Thanks. How can I reference the view controller in app delegate? - Zhu Shengqi

5 Answers

4
votes

I recommend you to add listeners for application changes:

- (void)registerNotifications {
    // Add observers to application state changes
    [[NSNotificationCenter defaultCenter]addObserver:self
                                            selector:@selector(applicationDidEnterBackground:)
                                                name:UIApplicationDidEnterBackgroundNotification
                                              object:nil];

    [[NSNotificationCenter defaultCenter]addObserver:self
                                            selector:@selector(applicationDidBecomeActive:)
                                                name:UIApplicationDidBecomeActiveNotification
                                              object:nil];
}
1
votes

Xcode no longer pays attention to the logging output from the iPhone Simulator after you terminate the program and return to Springboard. Everything still functions exactly the same except output won't go to Xcode's run log.

This is why you are unable to see any console output.

0
votes

I was looking for a solution to this for iOS8 and above with a single view application.

If you set:

Application does not run in background. NO

in your Info.plist file.

Then the viewWillDisappear and viewDidDisappear will be called.

Without it they were not being called.

0
votes

These life cycle methods don't work when putting the app in the background and foreground... I used these methods to connect and disconnect the socket so The easiest way is using NotificationCenter in SceneDelegate..

write following line

NotificationCenter.default.post(Notification(name: Notification.Name("appEnterForeground")))

in sceneWillEnterForeground

 NotificationCenter.default.post(Notification(name: Notification.Name("appEnterBackground")))

in sceneDidEnterBackground

write the following line in viewDidLoad

   NotificationCenter.default.addObserver(
        self,
        selector: #selector(myMethodonAppAcitve),
        name: Notification.Name(rawValue: "appEnterForeground"),
        object: nil
    )
    
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(myMethodonAppDeactive),
        name: Notification.Name(rawValue: "appEnterBackground"),
        object: nil
    )




@objc func myMethodonAppAcitve(){
        //do something when app is in forground
    }

@objc func myMethodonAppDeactive(){
        //do something when app is in background
    }
-1
votes

These two methods will not be called when you quit the app. Instead, the method - (void)applicationWillTerminate:(UIApplication *)application in AppDelegate.m will be called. You can do your operation in that method.