【原】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> 概述

  deallocNSObject的一个实例方法,用于回收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后,由于编译器会自动帮你释放内存,所有和内存相关操作retainreleaseautorelease,都不能写。

  当重写dealloc方法时, 也不能写[super dealloc],否则会报错。

 3> ARC的属性语义

 

 4> ARC 与 MRC 的混编

  如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Source ,在里面找到对应文件,添加flag:
      打开ARC:-fobjc-arc
      关闭ARC:-fno-objc-arc

 

posted @ 2016-03-30 19:19  墨隐于非  阅读(200)  评论(0编辑  收藏  举报