【原】iOS学习18之OC内存管理高级
1、属性的内存管理
1> 属性的语义特性
2> assign下的属性内部实现
1 @property (nonatomic, assign) NSString *name; 2 @synthesize name = _name; 3 // setter 4 - (void)setName:(NSString *)name { 5 _name = name; 6 } 7 // getter 8 - (NSString *)name { 9 return _name; 10 }
3> retain的内部实现
1 @property (nonatomic, retain) NSString *name; 2 @synthesize name = _name; 3 - (void) setName:(NSString *)name { 4 if (_name != name) { 5 [_name release]; 6 _name = [name retain]; 7 } 8 } 9 - (NSString *)name { 10 return [[_name retain] autorelease]; 11 }
4> copy的内部实现
1 - (void) setName:(NSString *)name { 2 if (_name != name) { 3 [_name release]; 4 _name = [name copy]; 5 } 6 } 7 - (NSString *)name { 8 return [[_name copy] autorelease]; 9 }
注:如果要对一个对象进行copy操作,那该对象所属的类必须遵守<NSCopying>协议
2、dealloc释放实例变量
1> 概述
dealloc是NSObject的一个实例方法,用于回收alloc开辟的内存空间。这个方法在对象引用计数为0时,由系统自动调用。
通常我们在dealloc中释放类的实例变量。
2> 内部实现
1 - (void)dealloc { 2 [_name release]; // 解决setter方法中存在的内存泄露 3 _name = nil; 4 [super dealloc]; 5 }
3> 注意事项
永远不要手动调 dealloc。
在dealloc方法的最后一行,必须要写[super dealloc],让系统真正的去销毁对象。
3、便利构造器的内存管理
1> 自定义初始化方法
1 - (instancetype)initWithName:(NSString *)name { 2 self = [super init]; 3 if (self) { 4 self.name = name; // 必须为self.,不然会出现Crash 5 } 6 return self; 7 }
2> 便利构造器的内部实现
1 + (instancetype)personWithName:(NSString *)name { 2 3 Person *person = [[Person alloc] initWithName:name]; 4 return [person autorelease]; 5 6 }
4、集合的内存管理
5、KVC
1> 概述
KVC:Key Value Coding,键值编码,是一种间接访问实例变量的方法。
KVC 提供了一个使用字符串(Key)而不是访问器方法,去访问一个对象实例变量的机制。
2> KVC中常用的方法
1 - (id)valueForKey:(NSString *)key; // 通过key值取值 2 - (void)setValue:(id)value forKey:(NSString *)key; // 赋值操作 3 - (id)valueForKeyPath:(NSString *)keyPath; // 通过路径访问变量 4 - (void)setValue:(id)value forKeyPath:(NSString *)keyPath; // 通过路径进行赋值操作 5 - (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues; // 同时给多个属性赋值
3> 通过KVC键值编码访问属性
① key值查找
1 [stu setValue:@"xiaoqiang" forKey:@"name"]; 2 [stu setValue:@"boy" forKey:@"gender"]; 3 [stu setValue:@24 forKey:@"age"]; 4 5 NSLog(@"name = %@, gender = %@, age = %@", [stu valueForKey:@"name"], [stu valueForKey:@"gender"], [stu valueForKey:@"age"]);
② 路径查找
1 Teacher *tea = [[Teacher alloc] init]; 2 3 stu.teacher = tea; 4 5 [stu setValue:@"fangfang" forKeyPath:@"teacher.name"]; 6 7 NSLog(@"teacherName = %@", [stu valueForKeyPath:@"teacher.name"]);
③ 同时给多个属性赋值
1 NSDictionary *dict = @{ 2 @"name" : @"fangfang", 3 @"gender" : @"girl", 4 @"age" : @18, 5 @"hobby" : @"fangfang" 6 }; 7 Student *stu2 = [[Student alloc] init]; 8 [stu2 setValuesForKeysWithDictionary:dict]; 9 10 NSLog(@"name = %@, gender = %@, age = %ld", stu2.name, stu2.gender, stu2.age);
4> KVC抛出异常的方法
① 使用KVC设置值对象时
如果当前类没有找到对象的Key值,系统会自动调用 setValue: forUndefinedKey: 方法
该方法的默认实现是抛出一个异常,如果不想抛出异常,就重写这个方法
1 // 重写 2 // 使用KVC设置值对象 3 - (void)setValue:(id)value forUndefinedKey:(NSString *)key { 4 NSLog(@"不存在Key:%@", key); 5 }
② 使用KVC取值的时候
如果当前类没有找到对应的Key值,系统会自动调用 valueForUndefinedKey: 方法
该方法的默认实现是抛出一个异常,如果不想抛出异常,就重写这个方法
1 // 重写 2 // 使用KVC取值的时候 3 - (id)valueForUndefinedKey:(NSString *)key { 4 5 return nil; 6 }
5> KVC的实现机制
KVC按顺序使用如下技术:
- 检查是否存在getter方法-<key>或者setter方法-set<key>:的方法;
- 如果没有上述方法,则检查是否存在名字为-_<key>、<key>的实例变量;
- 如果仍未找到,则调用 valueForUndefinedKey: 和 setValue: forUndefinedKey: 方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
6、ARC
1> 概述
ARC:Automatic Reference Counting,自动引用计数,由开发人员开辟内存空间,但是不需要释放该内存空间,由系统自动释放该空间。
ARC本质上还是基于MRC的,只不过是系统自动添加了释放内存的方法。
ARC是编译器特性,而不是运行时特性,更不是垃圾回收器(GC)。
从Xcode5.0后,创建的工程默认是开启ARC的。
2> ARC的注意事项
当工程开启ARC后,由于编译器会自动帮你释放内存,所有和内存相关操作retain、release、autorelease,都不能写。
当重写dealloc方法时, 也不能写[super dealloc],否则会报错。
3> ARC的属性语义
4> ARC 与 MRC 的混编
如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Source ,在里面找到对应文件,添加flag:
打开ARC:-fobjc-arc
关闭ARC:-fno-objc-arc