2009-05-18 15 views
23

Come si confrontano due oggetti di una classe personalizzata? La mia idea era di aggiungere un metodo aggiuntivo alla classe in cui posso confrontare l'oggetto corrente con un altro oggetto dello stesso tipo.Come faccio a confrontare gli oggetti in Objective-C?

Così posso scrivere il mio codice come viene confrontato ogni campo della classe.

Questo è come lo farei. O ci sono dei metodi predefiniti per farlo? Come "isEqualTo" della classe NSString?

risposta

53

I puntatori a -isEqual: sono buone, ma se si implementa -isEqual:, è assolutamente necessario implementare anche -hash in modo tale che, se due oggetti ritornano YES per -isEqual: saranno anche restituire lo stesso valore per -hash. L'implementazione di isEqual: senza implementare anche -hash causa alcuni bug molto sorprendenti quando si utilizzano le raccolte come NSArray.

Per i nuovi sviluppatori, tendo a raccomandare il sovraccarico di -isEqual:. Raccomando invece di utilizzare la stessa tecnica di NSString e creare un numero personalizzato -isEqualToFoo: (dove Foo è la tua classe) finché non comprendi l'impatto di -isEqual: sulle raccolte e desideri specificamente questo comportamento. Sovraccarico -isEqual: potente, ma i bug che è possibile creare sono sottili. Creare il tuo comparatore personalizzato è più sicuro e più chiaro in molti casi.

+0

Ciao Rob. Bella risposta! Dato che sono un "nuovo sviluppatore", farò esattamente come hai suggerito. Questo è quello che avevo in mente in primo luogo. Grazie molto. – TalkingCode

+0

Grazie per aver segnalato questo. Mentre ancora non capisco PERCHÉ isEqual non è abbastanza per determinare l'uguaglianza, stavo ottenendo un comportamento davvero strano di NSCountedSet perché non avevo idea che l'hash entrasse in gioco con i test di uguaglianza generici. – LucasTizma

+6

@LucasTizma È necessario implementare 'hash' perché è utilizzato per le ottimizzazioni. 'isEqual:' potrebbe essere molto costoso. Si consideri un enorme 'NSString'. Devi confrontare ogni personaggio. Invece, per prima cosa controlla "hash". Questo è un numero semplice, quindi il confronto è molto veloce e per le strutture di dati simili a un bucket lo hai già calcolato comunque. Se gli hash sono uguali, solo allora 'isEqual:' chiama. Va bene per due cose ineguali avere lo stesso hash, e il metodo di hash più semplice è 'return 1;'. Ma questo può danneggiare le prestazioni se ci sono molti controlli di uguaglianza e 'isEqual:' è costoso. –

6

Il metodo standard prevede l'override di - (BOOL)isEqual:(id)anObject e - (NSUInteger)hash.

Si consiglia di leggere la documentazione per NSObject protocol e this QUINTA domanda ha alcune risposte interessanti su come scrivere il proprio metodo di hash.

1

Guardare il isEqual: e il metodo compare:.

0

Ho il seguente oggetto:

#import <Foundation/Foundation.h> 

typedef NS_ENUM(NSUInteger, SeasonType) { 
    kWinter, 
    kSpring, 
    kSummer, 
    kFall 
}; 

@interface Season : NSObject 

@property (nonatomic) SeasonType season; 
@property (nonatomic) NSUInteger year; 

+(id) seasonWithYear:(NSInteger)year season:(SeasonType)season; 
-(id) initWithYear:(NSInteger)year season:(SeasonType)season; 

@end 

Quello che faccio è di base sovrascrittura NSObject metodi di confronto, non c'è bisogno di reinventare la ruota e il codice mantiene più pulito così:

#import "Season.h" 

@interface Season() 

@end 

@implementation Season 

+(id) seasonWithYear:(NSInteger)year season:(SeasonType)season{ 
    return [[self alloc] initWithYear:year season:season]; 
} 

-(id) initWithYear:(NSInteger)year season:(SeasonType)season{ 
    self = [super init]; 
    if (self) 
    { 
     _year = year; 
     _season=season; 
     _baseDate=nil; 
    } 

    return self; 
} 

#pragma mark - NSObject 

- (BOOL)isEqual:(id)object { 
    if (self == object) { 
     return YES; 
    } 

    if (![object isKindOfClass:[Season class]]) { 
     return NO; 
    } 

    return [self _isEqualToSeason:(Season *)object]; 
} 

- (NSUInteger)hash { 
    return self.season^self.year; 
} 


#pragma mark - Private/Internal 

- (BOOL)_isEqualToSeason:(Season *)season { 
    if (!season) { 
     return NO; 
    } 

    return ((!self.season && !season.season) || self.season == season.season) && 
    ((!self.year && !season.year) || self.year == season.year) ; 
} 

@end 

Usage:

Season *season2 = [Season seasonWithYear:2010 season:kFall]; 
Season *season3 = [Season seasonWithYear:2009 season:kFall]; 
[season2 isEqual:season3]; 
Problemi correlati