zoukankan      html  css  js  c++  java
  • 内存管理-ARC

    内存管理-ARC

    1、ARC内存管理本质

    OC的内存并不是在程序运行时监控使用的内存空间释放不需要使用的,而是在编译过程中由编译器在合适的位置添加内存管理代码,MRC机制下需要自己添加。本质上还是和C语言一样使用malloc申请空间,free释放空间,只不过是由系统添加。

    2、对象所有权修饰符

    四种修饰符__strong、__weak、__unsafe_retained、__autoreleasing

    __strong:
    使用__strong修饰的指针,会持有所指向的对象,即编译器会调用retain方法;当指针置为nil时,编译器会调用release方法。
    默认在创建指针但没有显示指明所有权修饰符的情况下,使用__strong修饰。
    // ARC
    Person * __strong p = [[Person alloc] init];
    p = nil;

    // MRC
    Person *p = [[Person alloc] init];
    [p retain];
    [p release];

    __weak:
    使用__weak修饰的指针,不会持有所指向的对象,即编译器不会调用retain方法;当指针置为nil时,编译器不会调用release方法。
    当对象没有持有者,即引用计数为0时,__weak修饰的指针会被编译器置为nil。
    一般使用__weak来解决循环引用的问题。
    Person * __strong p = [[Person alloc] init];
    Person * __weak p1 = p;
    p = nil; // 此时p1也被编译器置为nil。

    循环引用出现的条件:
      1.只有使用堆的数据结构才能发生循环引用。
      2.彼此都有属性指向对方。即对象中存在指向对方的属性。

    -------------Person-----------------
    @interface Person : NSObject
    @property (nonatomic, strong) Man *man;
    @end
    --------------Man---------------------
    @interface Man : NSObject
    @property (nonatomic, strong) Person *person;
    @end

    ---------------main-------------------
    void main(){
      Person *p = [[Person alloc] init];
      Man *m = [[Man alloc] init];
      p.man = m;
      m.person = p;
      //这样就满足出现循环引用的两个条件,都是保存在堆中,对象中存在指向对方的属性。
    }

    block这种数据结构,在ARC下使用block外部的变量会保存到堆中,如果使用的外部变量是对象时,会强引用该对象,形成上面的两个条件。

    __unsafe_retained:
    iOS5推出ARC时,为了兼容低版本中无弱引用,推出了__unsafe_retained,和weak的功能一样,只是在指向的对象释放时,指针不会被置为nil,造成野指针的现象。即使用__unsafe_retained修饰的指针不会被编译器管理,weak指针在对象释放时置为nil的动作时编译器添加的代码。


    __autoreleasing:
    用__autoreleasing修饰的变量,将对象赋值给该变量时,会自动将该变量加入到自动释放池。
    Person * __autoreleasing p = [[Person alloc] init]; // Person对象被自动添加到自动释放池中,相当于MRC下调用autorlease方法。
    等同于Person * __strong p = [Person person];

    函数或方法的参数和返回值一般用到自动释放池。
    +(id)person
    {
      Person *p = [[Person alloc]init];
      return p;
    }
    由于p变量的作用域在person方法内,当方法返回时p变量被销毁,为了防止Person对象被销毁,会将Person对象添加到自动释放池中。

    +(void)createPerson:(Person **p) // 隐藏了__autoreleasing,实际上为+(void)createPerson:(Person * __autoreleasing *p);
    {
      *p = [[Person alloc] init];
    }
    Person对象会被添加到自动释放池中。p指针在ARC下的内存管理为 “非自己创建并引用对象”。

    +(void)createPerson:(Person * __strong *p) // 显示声明为__strong,这样变量在ARC下的内存管理为 "自己创建并持有对象",对象不会加入到自动释放池
    {
      *p = [[Person alloc] init];
    }

    Person *p和Person **p1的所有权修饰符:
      p的修饰符为__strong,那么保存&p的变量的修饰符必须是__strong。即Person * __strong *pp = &p;
      Person **p1(其实显示的写法为Person * __autoreleasing * p1),因此p1 = &p;这样写编译器会报错。p为__strong而p1为__autoreleasing。
      对象指针和指向该对象指针的指针的所有权修饰符必须一致。
      Person * __weak p = nil;
      Person * __weak * p1 = &p;
      Person * __unsafe_retained p = nil;
      Person * __unsafe_retained p1 = &p;

  • 相关阅读:
    队列与双向队列

    linux nohup, jobs, fg, tail指令 指令前后台切换
    linux shell
    Linux学习笔记四 grep, sed, awk
    面试要求
    jenkins send files or publish
    mysql导入脚本
    第三方接口调用框架
    pdm文件name与comment互相同步
  • 原文地址:https://www.cnblogs.com/Zp3sss/p/8910290.html
Copyright © 2011-2022 走看看