对每个 属性 变化做点什么

Do something on each property change

我的 class 中有几个属性,我想在每次 属性 更改时调用 saveToFile

我不想覆盖每个 属性 的 setter。我应该覆盖吗 -[NSObject methodForSelector]?最好的方法是什么?

阅读 属性 观察员。 Swift中的示例:

var currentSession: Session? {
    didSet {
        if let session = self.currentSession {
            // Write session to file.
        }
    }
}

对于Objective-C,key-value observing可能更合适。

您想要的是键值观察或 KVO。 例如,您注册了一个每次 属性 更改时都会调用的方法。

如果您有一个文本字段并且想听取其文本的变化,您可以这样注册

[self.textField addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];

并且在您的 class 中,您将实现此方法:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    if ([keyPath isEqualToString:@"text"]) {

        NSLog(@"Textfield changed - MAKE CHANGES HERE");
    }

}

如果您不熟悉 KVO,这里有一个很好的教程: http://www.appcoda.com/understanding-key-value-observing-coding/

您可以注册为您想要监控的属性的观察者。 Cocoa's KVO 功能将在此处为您提供帮助。

基本上您需要调用 addObserver:forKeyPath:options:context: 并注册以便在属性更改时收到通知。发生这种情况时,运行时会在注册为观察者的对象上调用 observeValueForKeyPath:ofObject:change:context: 方法。你可以在这里做你想做的节省。

注册示例:

for(NSString *propName in self.propsIWantMonitored) {
    [self addObserver:self forKeyPath:propName change:0 context:@selector(saveToFile)];
}

以及处理 prop 值的变化:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    // make sure we don't interfere with other observed props
    // and check the context param
    if (context == @selector(saveToFile)) {
        [self saveToFile];
    }
}

以及注销:

for(NSString *propName in self.propsIWantMonitored) {
    [self removeObserver:self forKeyPath:propName context:@selector(saveToFile)];
}

上面的代码示例假设您已经声明了一组要监视的属性,您可以使用这些属性注册为观察者。您使用 context 参数来确定 observeValueForKeyPath 是否被调用作为对您刚刚注册的观察者的响应,以免与您的其他部分进行的其他 KVO 注册发生冲突 class.


解决您问题的替代方法(更节能)

上述方法有一个注意点:如果连续设置多个属性,那么saveToFile方法会在短时间内被多次调用,这可能会造成性能瓶颈并增加能源消耗您的应用程序。

另一种方法是设置一个 dirty 标志,该标志在 observeValueForKeyPath: 中设置并在 saveToFile 中重置。你可以saveToFile检查标志,如果对象不脏就不要使用文件系统。

您可以安排一个定期调用 saveToFile 的计时器,这样一次设置多个属性将导致只有一个磁盘访问。当您想要立即保存时,您可以随时手动调用 saveToFile

注意。我指的定时器是 GCD timer,因为 NSTimer 也会对您的应用程序产生负面能量影响。