内存管理的规则:
1.alloc创建的必须释放,便利构造器创建的不要释放
2.加入容器中的对象会被执行一次retain操作,引用计数加1
3.容器移除对象,会向对象发送一次release消息,让对象的引用计数减1
4.当容器释放的时候,会向容器中的所有对象发送一次release消息
当进行内存管理时,只要遵循每次增加都对应一次释放就不会出错。下面是一个例子:
定义一个Hero类,添加如下几个属性和初始化方法:
1 @property (nonatomic, copy) NSString *name; 2 @property (nonatomic, assign) NSInteger speed; 3 @property (nonatomic, retain) NSString *ability; 4 5 - (instancetype)initWithName:(NSString *)name speed:(NSInteger)speed ability:(NSString *)ability; 6 + (Hero *)heroWithName:(NSString *)name speed:(NSInteger)speed ability:(NSString *)ability;
在.m文件里一定要设置属性:
1 @synthesize name = _name; 2 @synthesize speed = _speed; 3 @synthesize ability = _ability;
接着实现初始化方法和销毁方法:
1 - (void)dealloc 2 { 3 //因为speed不是对象类型所以不需要释放内存 4 [_name release]; 5 [_ability release]; 6 [super dealloc]; 7 } 8 9 - (instancetype)initWithName:(NSString *)name speed:(NSInteger) speed ability:(NSString *)ability 10 { 11 self = [super init]; 12 if (self) 13 { 14 _name = name; 15 _speed = speed; 16 _ability = ability; 17 } 18 return self; 19 } 20 21 + (Hero *)heroWithName:(NSString *)name speed:(NSInteger) speed ability:(NSString *)ability 22 { 23 return [[[Hero alloc] initWithName:name speed:speed ability:ability] autorelease]; 24 }
以及setter和getter方法:
1 - (void)setName:(NSString *)name 2 { 3 if(_name != name) 4 { 5 [_name release]; 6 _name = [name copy]; 7 } 8 } 9 - (NSString *)name 10 { 11 return [[_name retain] autorelease]; 12 } 13 14 - (void)setAbility:(NSString *)ability 15 { 16 if(_ability != ability) 17 { 18 [_ability release]; 19 _ability = [ability retain]; 20 } 21 } 22 - (NSString *)ability 23 { 24 return [[ability retain] autorelease]; 25 }
KVC
Key Value Coding,键值编码,是一种间接访问实例变量的方法。
KVC提供了一种使用字符串(key)而不是访问器方法,去访问一个对象实例变量的机制。
常用方法:
- (id)valueForKey:(NSString *)key;通过key(实例变量名)获取实例变量的值。
- (void)setValue:(id)value forKey:(NSString *)key;通过key(实例变量名)给实例变量赋值。
- (id)valueForKeyPath:(NSString *)keyPath;通过keyPath获取实例变量的值。
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;通过keyPath给实例变量赋值。
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;将一个字典对象的键值对给对象的各个实例变量赋值。
注意!当使用KVC时,如果key值和属性名不一样时,就会崩溃。在解决该情况之前,先看看KVC的内部实现过程:
A.setValue:forKey:(假如给的key是name)
1.去类里面找是否有一个方法叫setName:,有的话赋值,没有的话执行第二步
2.去类里面找是否有一个叫_name的实例变量,有的话赋值,没有的话执行第三步
3.去类里面找是否有一个叫name的实例变量,有的话赋值,没有的话执行第四步
4.查找当前类是否实现了setValue:forUndefinedKey:方法,如果有,走方法内部实现,如果还没有,就会抛出异常,引起崩溃
B.valueForKey:(假设给的key是name)
1.去类里面找是否有一个方法叫getName:,有的话取值,没有的话执行第二步
2.去类里面找是否有一个叫_name的实例变量,有的话取值,没有的话执行第三步
3.去类里面找是否有一个叫name的实例变量,有的话取值,没有的话执行第四步
4.查找当前类是否实现了valueForUndefinedKey:方法,如果有,走方法内部实现,如果还没有,就会抛出异常,引起崩溃
所以为了防止崩溃情况的发生,只需要重新实现以下setValue:forUndefinedKey:和valueForUndefinedKey:这两个方法即可:
1 - (void)setValue:(id)value forUndefinedKey:(NSString *)key 2 { 3 4 } 5 6 - (id)valueForUndefinedKey:(NSString *)key 7 { 8 return nil; 9 }
setValue:forUndefinedKey:方法里可以填充与之相关的操作