2016-07-30 11 views
0

FactorHelper 정의가 아래에있는 Objective-C 클래스가 있습니다. 그것은 NSMutableArrayNSNumbers 인 요소라는 속성을 가지고 있습니다. 두 FactorHelper 개체의 factors 속성에 숫자가 다른 순서로있는 경우에도 true를 반환하는 사용자 지정 isEqual: 메서드가이 클래스에 있습니다. * [NSMutableSet addObject : X] * 이미 [Y isEqual : X] *가 이미 집합에있는 객체 Y에 대해 TRUE를 반환하더라도

나는 10,2,5와 10,5,2 및 다른 두 FactorHelper 객체 하나를 생성하여 테스트했습니다. 그런 다음 NSMutableSet을 만들고 firstObject를 추가 한 다음 두 번째 객체를 추가했습니다. 두 번째 개체가 추가되지 않을 것으로 예상했지만 추가 된 것을 볼 수 있습니다. 코드를 단계별로 실행하면 isEqual이 addObject에 의해 호출되고 TRUE을 반환한다는 것을 알게되었습니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까? [NSMutableSet new][NSMutableSet alloc] init]에 변경

UPDATE

예상대로 사물이 작동합니다.

또한 TRUE를 모두 변경하면 FALSE는 isEqual을 YES로 설정하고 NO를 설정하면 올바르게 동작합니다 ([NSMutableSet new]으로 유지하더라도).

나는 무슨 일이 일어나는지 전혀 모른다. 누군가가 약간의 빛을 비춰 줄 수 있습니까?!

클래스 정의

@interface FactorHelper: NSObject 
@property NSMutableArray <NSNumber *> *factors; 
-(BOOL) isEqual:(FactorHelper *)other; 
-(instancetype) initWithFactors:(NSMutableArray *)factors; 
-(NSString *) description; 
@end 

@implementation FactorHelper 

- (instancetype) initWithFactors:(NSMutableArray *)factors 
{ 
    self = [super init]; 

    if (self) { 
     _factors = factors; 
    } 

    return self; 
} 

-(BOOL) isEqual:(FactorHelper *)other 
{ 
    if ([self.factors count] != [other.factors count]) 
    { 
     return FALSE; 

    } 
    else 
    { 
     NSMutableDictionary <NSNumber *, NSNumber *> *myHashTable = [[NSMutableDictionary alloc] init]; 
     for (NSNumber *nextNumber in self.factors) { 
      if(myHashTable[nextNumber] == nil) 
      { 
       myHashTable[nextNumber] = @(1); 
      } 
      else 
      { 
       myHashTable[nextNumber] = @([myHashTable[nextNumber] integerValue]+1); 
      } 
     } 

     for (NSNumber *nextNumber in other.factors) 
     { 
      if(myHashTable[nextNumber] == nil) 
      { 
       return FALSE; 
      } 
      else 
      { 
       myHashTable[nextNumber] = @([myHashTable[nextNumber] integerValue] - 1); 

       if ([myHashTable[nextNumber] integerValue] == 0) { 
        [myHashTable removeObjectForKey:nextNumber]; 
       } 
      } 
     } 

     if ([[myHashTable allKeys] count] == 0) 
     { 
      return TRUE; 
     } 
     else 
     { 
      return FALSE; 
     } 

    } 
} 
@end 

단위 테스트 코드

NSMutableSet *testSet = [NSMutableSet new]; 
FactorHelper *fact1 = [[FactorHelper alloc] initWithFactors:[@[@(10),@(5),@(2)] mutableCopy]]; 
FactorHelper *fact2 = [[FactorHelper alloc] initWithFactors:[@[@(10),@(2),@(5)] mutableCopy]]; 
[testSet addObject:fact1]; 
[testSet addObject:fact2]; 
NSLog(@"Are factors 1 and 2 the same: %d",[fact1 isEqual:fact2]); 
+0

코드에서 NSMutableSet을 사용합니까? – Willeke

+0

testSet은 NSMutableSet입니다. 위의 주 코드에 추가되었습니다. 이 코드는 OS X 커맨드 라인 툴의 주요 메소드 내에 있습니다. 아래 내 대답을 참조하십시오. 모든 TRUE/FALSE를 YES/NO로 변경하면 문제가 해결됩니다. –

답변

2

NSMutableSet은 해시 값 기반 집합입니다. isEqual:과 일치하는 요소 유형에 대해 hash 메소드를 대체해야합니다. 이 같은 귀하의 경우에는

은 무엇인가 : 당신은 내가 그것을 추가되는 것을 볼 수 있지만,이 NSMutableSetFactorHelper 작업을하게 경우 확인 방법

- (NSUInteger)hash { 
    NSCountedSet *factorCounts = [[NSCountedSet alloc] initWithArray:self.factors]; 
    return [@"FactorHelper" hash] + [factorCounts hash]; 
} 

잘 모르겠어요.

그런데 isEqual:NSCountedSet을 사용하여 조금 더 짧게 구현할 수 있습니다.

-(BOOL) isEqual:(FactorHelper *)other { 
    NSCountedSet *myFactorCounts = [[NSCountedSet alloc] initWithArray:self.factors]; 
    NSCountedSet *otherFactorCounts = [[NSCountedSet alloc] initWithArray:other.factors]; 
    return [myFactorCounts isEqual:otherFactorCounts]; 
} 

위의 hash과의 명확한 일관성을 보여줍니다.

+0

감사합니다. 한 가지 질문 : 모든 Apple 컬렉션 클래스에 "해시"가 내장되어 있습니까? 예를 들어, CLassX라는 커스텀 클래스가 있다면, 그 속성은 NSArray * 배열과 NSInteger vale 두 가지 속성을 갖습니다. CLassX의 두 객체는 ​​배열과 값의 요소가있는 한 동일합니다. 해시를 [self.array hash] + [self.value hash]로 설정합니까? –

+0

@SmartHome, 내가 아는 한 모든 콜렉션 유형은 'isEqual :'메소드와 일치하는 해시 값을 반환합니다. 즉,'[col1 isEqual : col2]'가 TRUE를 반환하면'[col1 hash] == [col2 hash]'는 항상 TRUE가됩니다. ('NSArray * array','NSInteger value')에 대해 정의 된 동등성으로 해시를 구현하려면, [self.array hash] + (NSUInteger) self.value'가 작동합니다. (구현이 더 좋을 수도 있지만 그렇게 나쁘지는 않습니다.) – OOPer

+0

@SmartHome, "일관성이 효율적이라는 것을 의미하지는 않습니다." ''NSDictionary' 나'NSSet'과 같은 해시 기반 콜렉션에서 더 나은 성능을 얻으려면''[col1 hash] == [col2 hash] '의 가능성을 최소화하고'[col1 isEqual : col2]''는 필요하지 않습니다 . 애플의 프레임 워크에서의'hash '의 기본 구현은 그 목적에 가장 잘 부합되지 않을 수도 있습니다. – OOPer

1

귀하의 코드는 때때로에 나타난 경우에도 결코 작업 했다.

isEqual의 사용자 지정 구현이 클래스에서 클래스를 작업하기위한 유일한 요구 사항이 아니라는 점이 문제입니다. 생각 : 무엇 세트입니까? 해시 테이블입니다. 따라서 hash과 일치하는 사용자 지정 구현을 제공해야하며 그렇게하지 않았습니다.

해시 가능성에 대한 요구 사항은 두 개체의 해시 값이 같아야한다는 것입니다.