2009-05-18 6 views
23

¿Cómo comparo dos objetos de una clase personalizada? Mi idea era agregar un método adicional a la clase en el que pueda comparar el objeto actual con otro objeto del mismo tipo.¿Cómo comparo objetos en Objective-C?

De modo que puedo escribir mi propio código sobre cómo se compara cada campo de la clase.

Así es como lo haría. ¿O hay algunos métodos predefinidos para hacer eso? ¿Te gusta "isEqualTo" de la clase NSString?

Respuesta

53

Los punteros a -isEqual: son buenas, pero si se implementa -isEqual:, a pesar de todo deben también aplicar -hash de tal manera que si dos objetos regresan YES para -isEqual: también regresarán el mismo valor para -hash. Implementar isEqual: sin implementar también -hash conduce a algunos errores muy sorprendentes cuando utiliza colecciones como NSArray.

Para desarrolladores nuevos, tiendo a recomendar no sobrecargar -isEqual:. En su lugar, recomiendo usar la misma técnica que NSString y crear un -isEqualToFoo: personalizado (donde Foo es su clase) hasta que comprenda el impacto de -isEqual: en las colecciones y específicamente desee este comportamiento. Sobrecarga -isEqual: potente, pero los errores que puede crear son sutiles. Crear su propio comparador personalizado es más seguro y claro en muchos casos.

+0

Hi Rob. ¡Gran respuesta! Como soy un "nuevo desarrollador", haré exactamente lo que sugirió. Esto es lo que tenía en mente en primer lugar. Muchas gracias. – TalkingCode

+0

Gracias por señalar esto. Aunque todavía no entiendo POR QUÉ Equal no es suficiente para determinar la igualdad, estaba obteniendo un comportamiento REALMENTE extraño de NSCountedSet porque no tenía idea de que el hash entraba en juego con las pruebas genéricas de igualdad. – LucasTizma

+6

@LucasTizma Debe implementar 'hash' porque se usa para optimizaciones. 'isEqual:' podría ser muy costoso. Considere un 'NSString' masivo. Tienes que comparar cada personaje. En cambio, primero verifica 'hash'. Este es un número simple, por lo que la comparación es muy rápida, y para las estructuras de datos similares a un cubo ya lo ha calculado de todos modos. Si los hashes son iguales, solo entonces se llama a 'isEqual:'. Está bien que dos cosas desiguales tengan el mismo hash, y el método de hash legal más simple es 'return 1;'. Pero esto puede perjudicar el rendimiento si hay muchos controles de igualdad y 'isEqual:' es caro. –

6

La manera estándar es anular - (BOOL)isEqual:(id)anObject y - (NSUInteger)hash.

Debe leer la documentación para NSObject protocol y this ASÍ QUE la pregunta tiene algunas respuestas interesantes sobre cómo escribir su método hash.

1

Mire el isEqual: y el método compare:.

0

Tengo el siguiente objeto:

#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 

Lo que hago es la base de sobreescritura NSObject métodos de comparación, no hay necesidad de reinventar la rueda y el código mantiene más limpio, así:

#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 

Uso:

Season *season2 = [Season seasonWithYear:2010 season:kFall]; 
Season *season3 = [Season seasonWithYear:2009 season:kFall]; 
[season2 isEqual:season3]; 
Cuestiones relacionadas