美文网首页OC学习
OC 内存的高级管理

OC 内存的高级管理

作者: 李小六_ | 来源:发表于2015-05-10 15:04 被阅读151次

属性的属性, 是对内存的优化,! 这里具体讲解

  1. 属性的内部实现原理
  • assign
    assign的内部实现 // 定义变量的时候, 无原子性, 语义设置为assign;
    @property(nontatomic , assign)NSString *name;
    setter 方法
    - (void)setName:(NSString *)name {
    _name = name;
    }
    getter 方法
    - (NSString *)name {
    return _name;
    }
    调用!
    NSString *name = [[NSString alloc] initWithFormat:@"张三"];// 此时计数为1
    Person *p = [[Person alloc] init]; p引用计数为1
    [p setName:name] p指向存储name那块空间区域, p引用计数为1, name 引用计数为1;
    [name release] 则name计数减1为0, 则name那块空间被释放!
    NSLog:(@"%@", [p name]); p所指向的那块区域已不存在 ,p变为了野指针!也就是野指针异常 !
    [p release];
    所以, 当用alloc 创建的时候,出现了野指针的现象!

  • retain 把语义设置成retain试试
    @property(nontatomic , retain)NSString *name;
    - (void)setName:(NSString *)name {
    if (_name != name)
    [_name release];
    _name = [name retain];
    }
    getter方法
    -(NSString *)name{
    return[[_name retain ]autorelease];
    }

    按照以上方法再来一遍

      NSString *name = [[NSString alloc] initWithFormat:@"张三"]; // name引用计数为1 
      Person *p = [[Person alloc] init];  // p的引用计数为1;
      [p setName:name];  // 经内部实现, name引用计数为2; p指向name那块空间
      [name release];    // name引用计数为 1;
      NSLog(@"%@", [p name]);  
    
      NSString *newName = [[NSString alloc] initFormat:@"李四"];    // newName 计数为1;
      [p setName: newName];          {此时, 经过retain的内部实现, [_name release], 则name计数为0, name自动释放, 接着在执行_name = [name retain]; };           
      [newName release];  newName计数-1, 所以newName引用计数为1  
      [p release];  p引用计数为0, 自动释放
    
     此时, newName还没有完全被释放, 所以还有内存问题!!
    
  • copy 把语义设置成copy
    @property(nonatomic, copy)NSString *name;
    copy中的setter方法
    - (void)setName:(NSString *)name{
    if (_name != name){
    [_name release];
    _name = [name copy];
    }
    }
    getter方法;
    - (NSString *)name{
    return [[_name retain ] autorelease];
    }
    引用
    NSString *name = [[NSString alloc] initWithFormat:@"张三"]; //name引用计数为1
    Person *p = [[Person alloc] init]; // p 引用计数为1;
    [p setName: name]; // 拷贝了一份, 拷贝的_name 引用计数为1;p 指向 _name;
    [name release] // name 引用计数为0, 自动释放;
    NSLog(@"%@", [p name]);

     NSString *newName = [[NSString alloc] initWithFormat:@"李四"];  // setName引用计数为1;
     [p setName:newName];    //内部实现 [ _name release]  则name计数为0, 自动释放;_name = [name copy]; 则 copy了一份 newName 计数为1; p指向newName;
     [newName release];    // newName 计数为0;
     NSLog(@"%@", [p name]);
     [p release];   p 引用计数为0,  被释放,
    

    这有存在了与retain一样的问题, _newName没有被释放; 怎么解决?? 在delloc中处理

  • dealloc
    dealloc方法, 这个方法在引用计数为0的时候, 由系统自动调用, 使其释放! 因而可以重写delloc方法, 在调用的时候, 把上边有setter方法遗留下来的没有释放的给释放掉!

    比如 在person.m中重写delloc方法
    - (void)dealloc {
    [_name release]; // 释放setter方法泄露的实例变量
    [super dealloc];
    }

    当 p release之后, 引用计数变为0, 此时会调用dealloc方法, 因为释放了setter方法泄露的实例变量

  • dealloc的注意事项
    注意: 永远不要手动调用dealloc, 在dealloc方法的最后一行必须要写[super dealloc];

  • 遍历构造器的内存管理
    Person.m 中
    +(id)personWithName:(NSString *)name{
    Person *p = [[Person alloc] initWithName: name]; // 若是用遍历构造器, 这里的alloc 何时释放?
    return p;
    }
    若在 return p; 之前 [p release], retrun 则无返回;
    若在 retrun p; 之后[p release], 则也会出现, 无值现象;
    最佳方案
    +(id)personWithName:(NSString *)name{
    Person *p = [[Person alloc] initWithName: name];
    return [p autorelease];
    }

    return [p autorelease]是最完美的解决方案, 既不会出现内存泄露, 也不会产生野指针;

内存管理
NSString *houseOfMM = [[NSString alloc] initWithString:'装梵几的三室两厅'];

上面一段代码会执行以下两个动作:

  1. 在堆上分配一段内存用来存储@' 装梵几的三室两厅 ',比如:内存地址为0X1111 内容为' 装梵几的三室两厅'
  2. 在栈上分配一段内存用来存储 houseForWife ,比如:地址为 0XAAAA 内容自然为0X1111
    下面分别看下(assign,retain,copy):
  • assign的情况:
    NSString * myHouse = [ houseOfMM assign ];
    此时 myHousehouseOfMM 完全相同,地址都是 0XAAAA ,内容为 0X1111 ,即 myHouse 只是 houseOfMM 的别名,对任何一个操作就等于对另一个操作。因此 retainCount 不需要增加.(同进同出,关系好,一把钥匙,给我拿着)
  • retain的情况:
    NSString * myHouse = [ houseOfMM retain ];
    此时 myHouse 的地址不再为 0XAAAA ,可能为 0XAABB ,但是内容依然为 0X1111.因此 myHousehouseOfMM 都可以管理' 装梵几的三室两厅 '所在的内存。因此 retainCount 需要增加1.(有些独立,各自进出,两把钥匙)
  • copy的情况:
    NSString * myHouse = [ houseOfMM copy ];
    此时会在堆上重新开辟一段内存存放@'装梵几的三室两厅',比如0X1122,内容为@'装梵几的三室两厅',同时会在栈上为myHouse分配空间,比如地址:0XAACC,内容为0X1122,因此retainCount增加1供myHouse来管理0X1122这段内存.
    (两套@'装梵几的三室两厅',条件好,分居了,房子一人一套,所以钥匙一人一把。)
  • 什么时候用assign,当然是破房子,简装的房子拉
    基础类型(简单类型,原子类型):NSInteger,CGPoint,CGFloat,C数据类型(int,float,double,char等)
  • 什么时候用copy
    含有可深拷贝的mutable子类的类,如NSArray,NSSet,NSDictionary,NSData的,NSCharacterSet,NSIndexSet,NSString
    (可深度拷贝的房子)
    但是NSMutableArray这样的不可以,Mutable的不能用copy,不然初始化会有问题。切记
  • 什么时候用retain
    其他NSObject和其子类对象好嘛 (大多数)
    ARC中的strong相当于非ARC中的retain,ARC来了以后多搞一把钥匙就strong了啦。
  1. collection的内存管理
    collection 就是NSArray, NSDictionary, NSSet.....等容器类;
    collection 会自助管理自己内部的元素;
    加入collection中的对象会被retain;
    移除出collection的对象会被release;
    cellection被释放会对内部所有对象release;

  2. 多态;

    多态的特点;
    父类指针可以指向不同的子类对象;
    允许在多个类中定义同一个消息接口;
    可以屏蔽不同子类对象之间的差异, 写出通用代码;
    适应需求的不断变化;

相关文章

  • OC:内存管理高级☀️

    版权声明:本文为博主原创文章,未经博主允许不得转载。 一、基本原理 (一)为什么要进行内存管理。 由于移动设备的内...

  • OC 内存的高级管理

    属性的属性, 是对内存的优化,! 这里具体讲解 属性的内部实现原理 assignassign的内部实现 //...

  • 内存管理

    一.内存基本介绍 1、OC内存管理的基本概念 2、OC内存管理的范围​管理范围:管理任何继承自NSObject的对...

  • 内存管理

    目录一、内存分区 1、RAM和ROM 2、内存的五大分区二、内存管理 1、OC内存管理是指什么?OC内存管理的本质...

  • OC的内存管理

    1、OC的内存管理 OC是通过引用计数进行内存管理的,其核心思想遵循“谁创建谁释放;谁引用谁管理”。 OC的内存管...

  • Lesson 0-1 Objective-C basic

    6.OC 手动内存管理 OC 内存管理原则: 只要使用 alloc, new, copy, mutableCopy...

  • OC 基础 -------- > 内存管理 高级

    A --------- > 属性的语义特性 语义特性 使用范围 assign 基本数据类型( c...

  • iOS之从MRC到ARC内存管理详解

    概述 在iOS中开发中,我们或多或少都听说过内存管理。iOS的内存管理一般指的是OC对象的内存管理,因为OC对象分...

  • iOS五大块知识总结之内存管理

    1.1 管理的原因 只有OC对象才需要管理内存,非OC对象(如:char、int、folat)则不需要管理内存的本...

  • iOS 中堆和栈的区别以及冒泡排序

    在引入堆和栈之前,先要知道,iOS中的内存管理范围: OC对象需要进行内存管理,非oc对象不需要进行内存管理,比如...

网友评论

本文标题:OC 内存的高级管理

本文链接:https://www.haomeiwen.com/subject/whbafttx.html