iOS - 객체 동일성

7285 단어
Objective-C에서 대상의 상등성은 자주 무시되는 부분으로 개발 과정에서 isEqual, isEqual Tostring, ==를 사용하여 대상을 비교한다.Objective-C 만약 두 대상의 메모리 주소가 같다면 대상은 틀림없이 같고 대상의 본체성이라고 할 수 있다.만약 두 대상의 메모리 주소가 다르지만 다른 데이터가 모두 같다면 대상도 같고 등동성이라고 할 수 있다.
- (BOOL)isEqual:(id)obj {
    return obj == self;
}

Foundation 프레임워크에서 일반적으로 NSObject의 하위 클래스는 다음과 같은 고유의 동일성 검사를 수행합니다.
  • NSAttributedString -isEqualToAttributedString:
  • NSData -isEqualToData:
  • NSDate -isEqualToDate:
  • NSDictionary -isEqualToDictionary:
  • NSHashTable -isEqualToHashTable:
  • NSIndexSet -isEqualToIndexSet:
  • NSNumber -isEqualToNumber:
  • NSOrderedSet -isEqualToOrderedSet:
  • NSSet -isEqualToSet:
  • NSString -isEqualToString:
  • NSTimeZone -isEqualToTimeZone:
  • NSValue -isEqualToValue:

  • 대상이 같은지 아닌지를 비교하려면 간단하게 isEqual을 통해 대상을 비교하는 것이 아니라 상기 방법을 사용해서 비교하는 것을 권장합니다.

    문자열


    ==로 문자열을 판단하지 마십시오. 코드는 다음과 같습니다.
    NSString *str1 = @"FlyElephant";
        NSString *str2 = @"FlyElephant";
        
        NSLog(@"%p---%p",str1,str2);
        if (str1 == str2) {
            NSLog(@"     ");
        }
    

    의 코드는 우리가 기대하는 것은 같지 않지만 문자열이 머무르는 최적화 기술 때문에 모든 문자열은 하나의 공유 문자열 탱크에 있기 때문에 변하지 않는 문자열의 값을 서로 다른 지침에 부여한다.

    isEqual


    두 객체가 동일한지 비교하려면 특정 객체의 데이터를 기준으로 시스템 비교를 수행하여 Person 클래스를 구성하고 이름, 나이, 지역 세 필드를 정의해야 합니다.
    @interface Person : NSObject
    
    @property (copy, nonatomic) NSString *name;
    
    @property (assign, nonatomic) NSUInteger age;
    
    @property (copy, nonatomic) NSString *location;
    
    - (BOOL)isEqualToPerson:(Person *)person;
    
    @end
    
    - (BOOL)isEqualToPerson:(Person *)person {
        
        if (!person) {
            return NO;
        }
        
        BOOL isEqualName = (!self.name && !person.name) || [self.name isEqualToString:person.name];
        BOOL isEqualAge = self.age == person.age;
        BOOL isEqualLocation = (!self.location && !person.location) || [self.location isEqualToString:person.location];
        
        return isEqualName & isEqualAge & isEqualLocation;
    }
    

    두 Person이 동일한지 비교하려면 isEqualPeron을 통해 비교합니다.
       Person *person1 = [[Person alloc] init];
        person1.name = @"FlyElephant";
        person1.age = 27;
        person1.location = @"  ";
        
        Person *person2 = [[Person alloc] init];
        person2.name = @"FlyElephant";
        person2.age = 27;
        person2.location = @"  ";
        
        BOOL isEqulPerson = [person1 isEqualToPerson:person2];
        
        if (isEqulPerson) {
            NSLog(@"person1 person2  ");
        } else {
            NSLog(@"     ");
        }
    

    만약에 전달 대상이 자신이라면 이후의 판단을 할 필요가 없고 비교적 많은 비교 방법이 나타나지 않도록 isEqual 방법을 다시 쓰기 위해 isEqual ToPerson 방법을 그 안에 내장하면 된다.
    - (BOOL)isEqual:(id)object {
        if (self == object) {
            return YES;
        }
        
        if (![object isKindOfClass:[Person class]]) {
            return NO;
        }
        
        return [self isEqualToPerson:(Person *)object];
    }
    

    isEqual을 통한 판단 결과는 isEqualPerson 결과와 일치합니다.
       BOOL isEqual = [person1 isEqualToPerson:person2];
        if (isEqual) {
            NSLog(@"isEqual:person1 person2  ");
        } else {
            NSLog(@"isEqual:     ");
        }
    

    hash


    대상을 비교하는 과정에서 만약에 두 대상이 같다면hash값은 반드시 같고 두 대상의hash값은 같으며 대상이 반드시 같지 않다는 것을 자주 들을 수 있다.
    코드에서person1과person2를 비교하는 과정에서hash를 호출하지 않았습니다. 그러면 대상의hash방법을 언제 호출합니까?
    - (NSUInteger)hash {
        NSUInteger hash = [super hash];
        NSLog(@"Person  hash   = %ld", hash);
        return hash;
    }
    

    Objective-C 컬렉션 클래스, NSMutable Array, NSMutable Set, NSMutable Dictonary를 통해 Person 객체를 추가합니다.
        Person *person1 = [[Person alloc] init];
        person1.name = @"FlyElephant";
        person1.age = 27;
        person1.location = @"  ";
        
        Person *person2 = [[Person alloc] init];
        person2.name = @"FlyElephant1";
        person2.age = 28;
        person2.location = @"  ";
        
        NSMutableArray *arr1 = [[NSMutableArray alloc] initWithObjects:person1, nil];
        NSMutableArray *arr2 = [[NSMutableArray alloc] initWithObjects:person2, nil];
        
        NSLog(@"      ----------------------");
        NSMutableSet *set1 = [NSMutableSet set];
        [set1 addObject:person1];
        NSMutableSet *set2 = [NSMutableSet set];
        [set2 addObject:person2];
        NSLog(@"NSMutableSet     -------------------------------");
        
        NSMutableDictionary *dictionaryValue1 = [NSMutableDictionary dictionary];
        [dictionaryValue1 setObject:person1 forKey:@"dic1"];
        NSMutableDictionary *dictionaryValue2 = [NSMutableDictionary dictionary];
        [dictionaryValue2 setObject:person2 forKey:@"dic2"];
        NSLog(@"dictionary  person    -------------------------------");
        
        NSMutableDictionary *dictionaryKey1 = [NSMutableDictionary dictionary];
        [dictionaryKey1 setObject:@"1" forKey:person1];
        NSMutableDictionary *dictionaryKey2 = [NSMutableDictionary dictionary];
        [dictionaryKey2 setObject:@"2" forKey:person2];
        NSLog(@"dictionary  person     -------------------------------");
    
          ----------------------
    Person  hash   = 106102872298336
    Person  hash   = 106102872298336
    Person  hash   = 106102872298432
    Person  hash   = 106102872298432
    NSMutableSet     -------------------------------
    dictionary  person    -------------------------------
    Person  hash   = 106102872298336
    Person  hash   = 106102872298496
    Person  hash   = 106102872298432
    Person  hash   = 106102872298528
    dictionary  person     -------------------------------
    

    Person이 사전의 키 값으로 설정된 경우 NSCopying 프로토콜이 필요합니다.
    - (id)copyWithZone:(NSZone *)zone {
        Person *model = [[[self class] allocWithZone:zone] init];
        model.name = self.name;
        model.age  = self.age;
        model.location = self.location;
        return model;
    }
    

    해시 테이블(Hash Table)은 프로그램 설계의 기초적인 데이터 구조 중 하나로 NSSet과 NSDictionary가 원소를 매우 빠르게 찾을 수 있도록 한다.
    수조 중의 원소가 메모리에 분포하는 것은 연속적인 주소이기 때문에 어떤 원소가 존재하는지 판단할 필요가 있으면 점차적으로 훑어보아야 한다.
    산열표는 산열 함수를 통해 산열 값을 계산하여 원소의 고른 분포를 실현하고 서로 다른 원소가 같은 산열 값이 나타나면 산열 충돌이 발생한다.산열 목록 역시 원소의 산열 값을 통해 원소를 빨리 찾을 수 있다.
    NSSet은 원소의 산열 값에 따라 원소의 중복을 판단한다. NSDictionary에서 키는 중복될 수 없다. 모든 원소의 산열 값이 유일해야 하며 이 두 집합은 대상의hash 방법을 호출한다.
    서로 다른 원소의hash방법실현은 서로 다른 방식이 있을 수 있다. 만약에 시간대상이라면hash실현은 다음과 같다.
    - (NSUInteger)hash {
      return (NSUInteger)abs([self timeIntervalSinceReferenceDate]);
    }
    

    UIColor 객체의 경우 변위를 통해 다음을 수행할 수 있습니다.
    - (NSUInteger)hash {
      CGFloat red, green, blue;
      [self getRed:&red green:&green blue:&blue alpha:nil];
      return ((NSUInteger)(red * 255) << 16) + ((NSUInteger)(green * 255) << 8) + (NSUInteger)(blue * 255);
    }
    

    대신Matt Thompson의 조언: 대부분의 경우 우리는 관건적인 속성의 산열값에 대해 간단한 이소(XOR) 조작만 하면 99퍼센트의 상황에서 수요를 만족시킬 수 있다.
    - (NSUInteger)hash {
        return [self.name hash] ^ [self.location hash];
    }
    

    참고 링크: iOS-is Equal, is Equal To String과 == equality iOS 개발을 구별하는 것은 나에게 네가 정말 is Equal과hash를 안다고 말하지 마라!

    좋은 웹페이지 즐겨찾기