| 術語 | 英文 | 定義 | 檢查方式 |
|---|---|---|---|
| 同一性 | Identity | 兩個變數指向同一個記憶體位址 (同一實例) | == 指標比較 |
| 等值性 | Equality | 兩個不同實例但邏輯內容相同 | isEqual: 或型別專用方法 |
NSString *a = @"hello";
NSString *b = a; // 同一物件
NSString *c = [NSString stringWithString:@"hello"]; // 不同實例,內容相同
NSLog(@"a == b : %d", a == b); // 1 (同一性)
NSLog(@"a == c : %d", a == c); // 0 (不同實例)
NSLog(@"[a isEqual:c] : %d", [a isEqual:c]); // 1 (等值性)
@protocol NSObject
- (BOOL)isEqual:(id)object;
- (NSUInteger)hash; // 等值物件必須有相同 hash
@end
isEqual: 內部呼叫 ==,即僅判斷同一性。isEqual: 實作邏輯比較,同步覆寫 hash,否則放入 NSSet/NSDictionary 會失效。| 類別 | 比較依據 | 專用方法 |
|---|---|---|
NSString | 逐字元 Unicode 比較 | isEqualToString: (效能較佳) |
NSArray | 元素數量相同且逐項 isEqual: | — |
NSDictionary | 鍵值對數量相同、鍵 isEqual:、值 isEqual: | — |
NSNumber | 數值型別轉換後比較 | — |
NSDate | 時間間隔相等 | isEqualToDate: |
NSData | 位元組序列相同 | isEqualToData: |
// Person.h
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSUInteger age;
@end
// Person.m
@implementation Person
- (BOOL)isEqual:(id)object {
if (self == object) return YES; // 同一性快速路徑
if (![object isKindOfClass:[Person class]]) return NO; // 型別檢查
Person *other = (Person *)object;
return [self.name isEqual:other.name] && self.age == other.age;
}
- (NSUInteger)hash {
// 組合雜湊,確保等值物件 hash 相同
return [self.name hash] ^ (self.age << 1);
}
@end
isEqual: 忘記 hashPerson *p1 = [[Person alloc] initWithName:@"A" age:20];
Person *p2 = [[Person alloc] initWithName:@"A" age:20];
NSSet *set = [NSSet setWithObjects:p1, p2, nil];
NSLog(@"%lu", (unsigned long)set.count); // 輸出 2 (預期 1) —— hash 不同導致視為不同元素
isEqual: 不對稱[a isEqual:b] != [b isEqual:a] // 違反等價關係,容器行為未定義
修正:先檢查 isKindOfClass:,再比較屬性。
isEqualToString: 等),避免動態派發開銷。isEqual: 時必須覆寫 hash。hash 組合方式:return [prop1 hash] ^ ([prop2 hash] << 1) ^ ...。NSString) 提升效能。NSArray 等) 已正確實作深層比較,直接信任。若需排序,實作 compare: 回傳 NSComparisonResult:
- (NSComparisonResult)compare:(Person *)other {
NSComparisonResult nameCmp = [self.name compare:other.name];
if (nameCmp != NSOrderedSame) return nameCmp;
return (self.age < other.age) ? NSOrderedAscending : NSOrderedDescending;
}
同一性 = 指標相等 (==),極快;
等值性 = 語義相等 (isEqual:),需正确实作 hash。
記住黃金法則:if ([a isEqual:b]) assert([a hash] == [b hash]);