如何确定具有大量属性的对象(self)是否已更改? [英] How do you determine if an object (self) with a lot of properties has been changed?

查看:108
本文介绍了如何确定具有大量属性的对象(self)是否已更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题的简短版本:

我有一个有大量声明属性的类,我想跟踪是否有任何更改为此,当我在其上调用 save 方法时,它不会在不需要时写入数据库。如何更新 isDirty 属性而无需为所有声明的属性编写自定义setter

The short version of the question:
I have a class with a ton of declared properties, and I want to keep track of whether or not there have been any changes to it so that when I call a save method on it, it doesn't write to the database when it isn't needed. How do I update an isDirty property without writing custom setters for all of the declared properties?

问题的较长版本:

假设我有这样的课程:

The longer version of the question:
Let's say that I have a class like this:

@interface MyObject : NSObject
{
@property (nonatomic, retain) NSString *myString;
@property (nonatomic, assign) BOOL     myBool;
// ... LOTS more properties
@property (nonatomic, assign) BOOL     isDirty;
}

...

@implementation MyObject
{
@synthesize myString;
@synthesize myBool;
// ... LOTS more synthesizes :)
@synthesize isDirty;
}

尝试1

我的第一个想法是实现 setValue:forKey:这样:

- (void)setValue:(id)value forKey:(NSString *)key {
    if (![key isEqualToString:@"isDirty"]) {
        if ([self valueForKey:key] != value) {
            if (![[self valueForKey:key] isEqual:value]) {
                self.isDirty = YES;
            }
        }
    }
    [super setValue:value forKey:key];
}

这直到您使用setter直接设置值(即 myObject.myString = @new string; ),在这种情况下, setValue:forKey:未被调用(我'我不知道为什么我认为它会,lol)。

This works perfectly until you set the value directly with a setter (i.e. myObject.myString = @"new string";), in which case setValue:forKey: isn't called (I'm not sure why I thought that it would be, lol).

尝试2

观察自我的所有属性。

Attempt 2
Observe all properties of self.

- (id)init
{
    // Normal init stuff
    // Start observing all properties of self
}

- (void)dealloc
{
    // Stop observing all properties of self
}

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
{
    // set isDirty to true
}  

我很漂亮确定这会奏效,但我认为必须有更好的方法。 :)
我也希望这是自动的,这样我就不必维护要监视的属性列表。我可以很容易地看到在保持这种状态时忘记将属性添加到列表中,然后试图找出为什么我的对象有时没有被保存。

I'm pretty sure that this will work, but I think that there must be a better way. :) I also want this to be automatic, so that I don't have to maintain a list of properties to watch. I can easily see forgetting to add a property to the list when maintaining this down the road and then trying to figure out why my object sometimes doesn't get saved.

希望我忽略了解决这个问题的简单方法!

Hopefully I'm overlooking a much simpler approach to this problem!

最终解决方案

请参阅下面的答案以获得最终解决方案。它基于Josh Caswell提供的答案,但是是一个有效的例子。

Final Solution
See my answer below for my final solution to this. It is based on the answer provided by Josh Caswell, but is a working example.

推荐答案

这里有一点反省应该有所帮助。 运行时功能可以为您提供所有对象属性的列表。然后你可以用它们告诉KVO dirty 依赖。这避免了必须手动更新属性列表的可维护性问题。需要注意的是,与任何其他涉及KVO的解决方案一样,如果直接更改了ivar,您将不会收到通知 - 所有访问必须通过setter方法。

A little introspection should help out here. The runtime functions can give you a list of all the object's properties. You can then use those to tell KVO that dirty is dependent on that list. This avoids the maintainability problem of having to update the list of properties by hand. The one caveat is that, like any other solution involving KVO, you won't be notified if the ivar is changed directly -- all access must be through setter methods.

init中注册以观察 self 键路径,并添加此方法,创建并返回 NSSet ,其中包含所有类属性的名称( @dirty除外) ,当然)。

Register to observe self's dirty key path in init, and add this method, creating and returning an NSSet with the names of all the class's properties (except @"dirty", of course).

#import <objc/runtime.h>

+ (NSSet *)keyPathsForValuesAffectingDirty 
{
    unsigned int num_props;
    objc_property_t * prop_list;
    prop_list = class_copyPropertyList(self, &num_props);

    NSMutableSet * propSet = [NSMutableSet set];
    for( unsigned int i = 0; i < num_props; i++ ){
        NSString * propName = [NSString stringWithFormat:@"%s", property_getName(prop_list[i])];
        if( [propName isEqualToString:@"dirty"] ){
            continue;
        }
        [propSet addObject:propName];
    }
    free(prop_list);

    return propSet;
}

现在观察。 (请注意,超类中定义的属性不包含在该列表中。)

Now an observation of dirty will be triggered whenever any of this class's properties are set. (Note that properties defined in superclasses are not included in that list.)

您可以使用该列表单独注册为所有名称的观察者。

You could instead use that list to register as an observer for all the names individually.

这篇关于如何确定具有大量属性的对象(self)是否已更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆