当我们自定义一个类的时候,要考虑到以下几个方面。
持久化保存、作为Hash的key、判断对象是否相等、对象的拷贝等
- 首先持久化保存
实现NSCoding协议,实现编码和解码的方法
-(void)encodeWithCoder:(NSCoder *)aCoder;
-(instancetype)initWithCoder:(NSCoder *)aDecoder;
存
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"user"];
取
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSData *data = [user objectForKey:@"user"];
User *user = [NSKeyedUnarchiver unarchiveObjectWithData:data];
- 对象作为Dictonary的key,或者具有拷贝的功能,就要实现NSCopying协议和拷贝的方法,还要重写hash方法。
- (id)copyWithZone:(NSZone *)zone
{
TestObj *obj = [[[self class] allocWithZone:zone] init];
obj.identifier = self.identifier;
obj.name = self.name;
return obj;
}
作为字典中的key的时候,他会重新拷贝一份,所以需要遵守NSCopying协议,并实现拷贝方法,字典的value对存入的对象是强引用的,这个要注意。
-(void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;
根据这个方法可以看到akey必须遵守NSCopying协议。
- 判断两个对象是否相等,或者要将我们自定义的对象添加到NSSet中或者作为字典的key的时候,需要经过hash计算,判断值在set中是否存在,判断值在字典中存储的位置。
重写
- (NSUInteger)hash;
- (BOOL)isEqual:(id)object;
- (BOOL)isEqual:(id)object {
if (self == object) { // 判断的是对象的地址
return YES;
}
if (![object isKindOfClass:[Person class]]) { //判断的是类型是否相同
return NO;
}
return [self isEqualToPerson:(Person *)object];
}
- (BOOL)isEqualToPerson:(Person *)person {
if (!person) { // 进入条件
return NO;
}
BOOL haveEqualNames = (!self.name && !person.name) || [self.name isEqualToString:person.name];
BOOL haveEqualBirthdays = (!self.birthday && !person.birthday) || [self.birthday isEqualToDate:person.birthday];
return haveEqualNames && haveEqualBirthdays; // 所有属性都满足相等才相等
}
- (NSUInteger)hash {
return [self.name hash] ^ [self.birthday hash];
}
hash函数在对象被加入到set中,或者当成字典的key的时候被调用,如果两个对象的hash值是一样的,那么再进行的就是equal判断,如果两个函数返回都相等,则对象存在set或者字典中。
那么我们在实现类的时候
KeyValuePairs.h
#import <Foundation/Foundation.h>
@interface KeyValuePairs: NSObject <NSCopying, NSCoding >
@property (nonatomic,strong)NSString *identifier;
@property (nonatomic,strong)NSString *name;
@end
KeyValuePairs.m
#import "KeyValuePairs.h"
@implementation KeyValuePairs
- (id)copyWithZone:(NSZone *)zone
{
KeyValuePairs *kvp = [[[self class] allocWithZone:zone] init];
kvp.identifier = self.identifier;
kvp.name = self.name;
return kvp;
}
- (BOOL)isEqualToKeyValuePairs:(KeyValuePairs *)kvp{
if (!kvp) {
return NO;
}
BOOL haveEqualName = (!self.name && !kvp.name) || [self.name isEqualToString:kvp.name];
BOOL haveEqualIdentifier = (!self.identifier && !kvp.identifier) || [self.identifier isEqualToString:kvp.identifier];
return haveEqualName && haveEqualIdentifier;
}
#pragma mark -NSObject
-(BOOL)isEqual:(id)object{
if (self == object) {
return YES;
}
if (![object isKindOfClass:[KeyValuePairs class]]) {
return NO;
}
return [self isEqualToKeyValuePairs:(KeyValuePairs *)object];
}
- (NSUInteger)hash {
return [self.name hash] ^ [self.identifier hash];
}
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self. name forKey:@"name"];
[aCoder encodeObject:self. identifier forKey:@"identifier"];
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
self. identifier = [aDecoder decodeObjectForKey:@"identifier"];
self. name = [aDecoder decodeObjectForKey:@"name"];
}
return self;
}
@end