1

I'm writing an iOS app using Swift and want to get notified of NSUserDefault changes. When I register an observer and try to modify the NSUserDefault data afterwards, I always get the following runtime error: EXC_BAD_ACCESS

I've created a little sample app to demonstrate the problem:

import UIKit

class ViewController: UIViewController {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector(observeUserDefaults()), name:
                    NSUserDefaultsDidChangeNotification, object: nil)
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: NSUserDefaultsDidChangeNotification, object: nil)
    }

    @IBAction func buttonPressed(sender: UIButton) {
        let userDefaults = NSUserDefaults.standardUserDefaults()
        userDefaults.setObject("test", forKey: "test")
        userDefaults.synchronize()
    }

    func observeUserDefaults() {
        NSLog("observeUserDefaults() called")
    }

}

The method "buttonPressed()" is linked to a UI button on the storyboard. As soon as I press the button, the app stops at "userDefaults.setObject("test", forKey: "test")" with error "EXC_BAD_ACCESS (code=1, address=0x0)" The code runs fine if I don't add the observer though.

I've created the same app using Objective-C, which runs without any problems:

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(observeUserDefaults) name:NSUserDefaultsDidChangeNotification object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];
}

- (IBAction)buttonPressed:(UIButton *)sender {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:@"test" forKey:@"test"];
    [userDefaults synchronize];
}

- (void)observeUserDefaults {
    NSLog(@"observeUserDefaults() called");
}

@end

Any ideas what is going wrong with the Swift app? Thanks for your help!

I'm running Xcode 6.1 using the iOS 8.1 SDK.

Greetings, Felix

Felix
  • 776
  • 8
  • 16

1 Answers1

2

The main error in

addObserver(self, selector: Selector(observeUserDefaults()), ...)

is that you call the method instead of providing its selector name:

addObserver(self, selector: Selector("observeUserDefaults"), ...)

Moreover, the selector should be a method taking a notification object:

- (void)observeUserDefaults(notification: NSNotification) {
    NSLog(@"observeUserDefaults() called");
}

Then the registration is

NSNotificationCenter.defaultCenter().addObserver(self,
                   selector: Selector("observeUserDefaults:"),
                   name: NSUserDefaultsDidChangeNotification,
                   object: nil)
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382