1

I have some code that changes the text of a UILabel, it works fine when the app is run first time around but when I close it (app goes to background) and then I reopen it, the UILabel is nil and the text can't be set again.

The text is set to the UILabel in viewDidLoad() function and I call viewDidLoad() in applicationWillEnterForeground function to set the text to the UILabel again - that's when it crashes giving the error fatal error: unexpectedly found nil while unwrapping an Optional value. I debugged it and the nil found is the UILabel

Here is some of the code in AppDelegate.swift:

func applicationWillEnterForeground(application: UIApplication) { 
     ViewController().refresh() 
}

And in ViewController.swift:

func refresh() {
    self.viewDidLoad()
}

Do you have any ideas why the UILabel becomes nil when the app goes to background?

sachalondon
  • 165
  • 1
  • 11
  • 1
    You should never explicitly call `viewDidLoad` `viewWillAppear` etc. How are you getting the reference to the view controller in `applicationWillEnterForeground` ? Please show the code in this method – Paulw11 Nov 23 '14 at 23:48
  • Here is the function `func applicationWillEnterForeground(application: UIApplication) { ViewController().refresh() }` and in ViewController: `func refresh() { self.viewDidLoad() }` – sachalondon Nov 23 '14 at 23:56
  • You should edit your question to include your code - see the "edit" link under the tags. What is `ViewController` - is it a property? How is it set? Also you should refactor - never call `viewDidLoad` - if you want to re-use set up code then move that code to another function and have `viewDidLoad` call it – Paulw11 Nov 23 '14 at 23:58
  • Ok I edited the question. I am not sure if the way I call the `refresh` function (present in the file `ViewController.swift`) is the correct way to do it.. – sachalondon Nov 24 '14 at 00:03
  • 1
    Looks like you're creating a new `ViewController` instead of getting a reference to your existing one. This would explain why your label is `nil`. – Aaron Brager Nov 24 '14 at 00:05
  • 1
    I want to understand how `ViewController` gets its value (it should be `viewController` by the way - variables start with a small letter, classes with a capital) - I suspect that the contents of `ViewController` is an instance that isn't instantiated by your storyboard so you get nil for the IBOutlets – Paulw11 Nov 24 '14 at 00:06
  • @AaronBrager @Paulw11 Yes you are right, but how do I create a reference to my `ViewController` then? – sachalondon Nov 24 '14 at 00:07
  • 1
    I would recommend that you don't. Your view controller should subscribe to the events that are posted when your application becomes active - http://stackoverflow.com/questions/26680287/uiapplicationdidbecomeactive-vs-uiapplicationwillenterforeground-difference – Paulw11 Nov 24 '14 at 00:09
  • Okay, so what is the code I have to put `applicationDidBecomeActive` (if I understand well, it is the best way) ? – sachalondon Nov 24 '14 at 00:12

1 Answers1

1

Rather than trying to hold a reference to your view controller from your app delegate, it is better to simply have your view controller subscribe to the foreground entry event -

In your viewDidLoad add the following

NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("enteringForeground:"),
  name: UIApplicationWillEnterForegroundNotification, object: nil)

The add a function to your ViewController

func enteringForeground(notification: NSNotification) {
   // Whatever you need to do to refresh UI
   // DO NOT CALL viewDidLoad
}

deinit {

   NSNotificationCenter.defaultCenter().removeObserver(self)

}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • You should remove the observer before the view controller is deallocated. From the NSNotificationCenter docs: "You must invoke `removeObserver:` or `removeObserver:name:object:` before any object specified by `addObserverForName:object:queue:usingBlock:` is deallocated." – Aaron Brager Nov 24 '14 at 00:22