如何比较两个NSObject的结构/属性的相等性

时间:2012-02-01 03:48:52

标签: iphone ios class nsobject

我有一个数据库模型NSObject类,有100个左右的属性 - 主要是NSStrings但有些NSDates。 我正在尝试确定一种简单的方法来比较数据库的任何两个给定成员对象。例如,如果用户在objectA中编辑属性,我希望能够与DB中的原始对象进行比较,以查看是否进行了更改。

[objectA isEqual:objectB]不会返回有效结果

所以我所做的是覆盖类定义中的isEqual方法,但这似乎很乏味。我还必须检查每个属性,看看其中任何一个是否为Nil,因为如果其中一个是Nil,那么比较看起来不起作用。

4 个答案:

答案 0 :(得分:1)

也许您可以使用KVC使{{​​1}}覆盖更加简洁。

首先,您必须准备一个代表每个属性名称的NSString数组,可能是isEqual方法。

init

- (id) init { // Other implementation of init self.propertyNames = [NSArray arrayWithObjects:@"property1", @"property2", @"property3", ... @"propertyN", nil]; } 方法中,您将查看所有属性名称并使用isEqual方法获取属性值。

valueForKey

这样,您就不必实现100个相同的序列。

上面的代码非常粗糙(没有空检查。没有参数对象的类型检查等),没有经过测试,但我希望你能理解。

另外需要注意的是,您还必须覆盖- (BOOL) isEqual : (id) object { for(NSString * propertyName in self.propertyNames) { id obj1 = [self valueForKey:property]; id obj2 = [object valueForKey:property]; if([obj1 isKindOfClass:NSStringFromClassName(@"NSString")]) { if(![obj2 isKindOfClass:NSStringFromClassName(@"NSString")]) return NO; NSString * strObj1 = (NSString *)obj1; NSString * strObj2 = (NSString *)obj2; if(![strObj1 isEqualToString:strObj2]) return NO; } if([obj1 isKindOfClass:NSStringFromClassName(@"NSDate")]) { if(![obj2 isKindOfClass:NSStringFromClassName(@"NSDate")]) return NO; NSDate * dateObj1 = (NSDate *)obj1; NSDate * dateObj2 = (NSDate *)obj2; if(![dateObj1 isEqualToDate:dateObj2]) return NO; } } return YES; } 方法。以下是NSObject documentation

的引用
hash

答案 1 :(得分:0)

isEqual:比较指针,这意味着除非它们是完全相同的对象,否则它们将不相等。你想要做的是使用compare:方法,它将实际比较NSStrings的内容。看看documentation,您可以指定几个选项,即使是区分大小写或不敏感的搜索。 NSDate有类似的方法比较,但你也可以这样做:

– isEqualToDate:
– earlierDate:
– laterDate:

看一下那个documentation

编辑:

NSStrings也有isEqualToString:方法,您可以这样做:

[objectA isEqualToString:objectB]

这将返回YES或NO,具体取决于objectA和objectB的unicode是否完全相同。如果你只想测试精确副本之间的相等性,那么这将是一个更好的选择,如果你想根据区分大小写compare:这样的某些选项进行比较是更好的选择。

答案 2 :(得分:0)

基于valueForKey:的方式略显乏味,但它有自己的性能权衡。

- (BOOL) isEqual: (id) obj
{
    if ([self class] != [obj class])
        return NO;

    NSArray *myProperties = ...;
    for (NSString *propertyName in myProperties) {
        if (![[self valueForKey:propertyName] isEqual: [obj valueForKey:propertyName]])
            return NO;
    }

    return YES;
}

答案 3 :(得分:0)

在这里发布工作代码以防万一它会帮助其他人 - 这个代码考虑一个或两个对象为空(不会使用isEqual进行比较):

在对象模型中合成propertyNames: 使用ProperyNames使用数组字符串数组初始化一次:

-(void)initPropertyNamesArray {
    propertyNames = [[NSArray alloc] initWithObjects:
                     @"lastName",
                     @"firstName",
                     @"dob",
                     @"notes", ..., nil];
}

覆盖isEqual:方法 (这个例子比较了我在模型中使用的对象类型 - 字符串,日期和图像):

    - (BOOL) isEqual:(Patient *)otherPatient {
    if (!self.propertyNames) [self initPropertyNamesArray];
    BOOL showLog = YES;
    if (showLog) NSLog(@"Patient ISEQUAL");
    for(NSString *property in self.propertyNames) {
        id obj1 = [self valueForKey:property];
        id obj2 = [otherPatient valueForKey:property];
        if (showLog) NSLog(@"Comparing %@:", property);

         //CHECK IF ONE OR THE OTHER IS NULL -- the're not equal if so
        if (! (obj1 && obj2)) {
            if ((obj1 && !obj2) || (!obj1 && obj2)) {
                if (showLog) NSLog(@"%@ is null %@ is not!", obj1?@"TO:":@"FROM:", obj2?@"TO:":@"FROM:");
                return NO;
            }
        }

        //STRING
        if([obj1 isKindOfClass:[NSString class]]) {
            if(![obj2 isKindOfClass:[NSString class]])
                return NO;

            NSString * strObj1 = (NSString *)obj1;
            NSString * strObj2 = (NSString *)obj2;
            if (strObj1 && strObj2) { 
                if (![strObj1 isEqualToString:strObj2]) {
                    if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, strObj1, strObj2);
                    return NO;
                }
            } else if (! (!strObj1 && !strObj2)) { //one is nil one isn't NOT EQUAL
                if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, strObj1, strObj2);
                return NO; 
            } 
            //both nil (call them equal) 

        //DATE    
        } else if([obj1 isKindOfClass:[NSDate class]]) {
            if(![obj2 isKindOfClass:[NSDate class]])
                return NO;

            NSDate * dateObj1 = (NSDate *)obj1;
            NSDate * dateObj2 = (NSDate *)obj2;
            if (dateObj1 && dateObj2) { 
                if (![dateObj1 isEqualToDate:dateObj2]) {
                    if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, dateObj1, dateObj2);
                    return NO;
                }
            } else if (! (!dateObj1 && !dateObj2)) { //one is nil one isn't NOT EQUAL
                if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, dateObj1, dateObj2);
                return NO; 
            } 
            //both nil (call them equal)

        //IMAGE
        } else if([obj1 isKindOfClass:[UIImage class]] && ![property isEqual:@"lastUpdated"]) {
            if(![obj2 isKindOfClass:[UIImage class]])  
                return NO;

            UIImage * imgObj1 = (UIImage *)obj1;
            UIImage * imgObj2 = (UIImage *)obj2;
            if (imgObj1 && imgObj2) {  //check both not nil
                if(![imgObj1 isEqual:imgObj2]) {
                    if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, imgObj1, imgObj2);
                    return NO;
                }
            } else if (! (!imgObj1 && !imgObj2)) { //one is nil one isn't NOT EQUAL
                if (showLog) NSLog(@"%@ changed from:%@ to:%@", property, imgObj1, imgObj2);
                return NO; 
            } 
            //both nil (call them equal)
        }
        if (showLog) NSLog(@"OK!");
    }
    if (showLog) NSLog(@"PATIENTS ARE THE SAME!");
    return YES;
}

你显然可以取出我为调试而放入的所有NSLog。 感谢所有帮助过我的人!