2

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
Zhu Shengqi
  • 3,632
  • 3
  • 24
  • 29
  • Are you closing or killing the app? – Pablo A. Apr 20 '15 at 09:12
  • 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 Apr 20 '15 at 09:14
  • 1
    use applicationWillTerminate: in app delegate. – aBilal17 Apr 20 '15 at 09:16
  • what is deployment target? because if it is less then 7.0 then applicationWillTerminate not called when you terminate the application. – Chirag Shah Apr 20 '15 at 09:18
  • @aBilal17 Thanks. How can I reference the view controller in app delegate? – Zhu Shengqi Apr 20 '15 at 09:25
  • its so simple just use notification or delegate. let me share some code of notification with you – aBilal17 Apr 20 '15 at 09:29
  • //Code in view controller //register to listen for event in view controller viewwillappear [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(eventHandler:) name:@"eventType" object:nil ]; //event handler when event occurs -(void)eventHandler: (NSNotification *) notification { NSLog(@"event triggered"); } //Add this in appdelegate method [[NSNotificationCenter defaultCenter] postNotificationName:@"eventType" object:nil ]; – aBilal17 Apr 20 '15 at 09:36
  • @Anupam Apple documentation says "Be sure to invoke removeObserver:name:object: before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated." Observers are no removed automatically. – Zhu Shengqi Apr 20 '15 at 09:40
  • @aBilal17 Thanks for the code. I also want to know how to get a reference pointing to view controller in appdelegate. I mean in view controller "self" is the observer, so removing it is easy. In appdelegate I need a reference to the view controller to perform removeObserver(). – Zhu Shengqi Apr 20 '15 at 09:49
  • @Anupam I can't use this solution. I want to get notified when applicationWillResignActive() fires, so I can save my data to disk. If I remove the observer in this method, then I will not be notified when the next time app resign active. – Zhu Shengqi Apr 20 '15 at 09:53

5 Answers5

5

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];
}
Pablo A.
  • 2,042
  • 1
  • 17
  • 27
1

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.

Servy
  • 202,030
  • 26
  • 332
  • 449
Charles Robertson
  • 1,760
  • 16
  • 21
0

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.

birdman
  • 1,134
  • 13
  • 13
0

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
    }
Wahab Khan Jadon
  • 875
  • 13
  • 21
-1

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.

Lazy_Clutch
  • 130
  • 3
  • 14