zoukankan      html  css  js  c++  java
  • 自动引用计数

    1.1 什么是自动引用计数

    自动引用计数是指内存管理中对引用采取自动计数的技术

    1.2 内存管理/引用计数

    生成并持有对象:alloc/new/copy/mutableCopy

    持有对象:retain

    释放对象:release

    废弃对象:dealloc

    自己生成的对象,自己所持有:

    id obj = [[NSObject alloc] init]; // 指向 生成并持有对象的指针 被赋值给变量obj

    非自己生成的对象,自己也能持有:

    id obj = [NSMutableArray array]; // 取得的对象存在,但自己不持有对象  NSMutableArray类对象被赋值给obj,但变量obj自己并不持有该对象

    [obj retain]; // 使用retain方法可以持有对象

    不在需要自己持有的对象时释放:

    id obj = [[NSObject alloc] init]; // 自己生成并持有对象

    [obj release]; // 释放对象

    用某个方法生成对象,并将其返回给该方法的调用方:

    - (id) allocObject {

        id obj = [[NSObject alloc] init];

        return obj;

    }

    原封不动地返回用alloc方法生成并持有的对象,就能让调用方也持有该对象。

    调用[NSMutableArray array]使取得的对象存在,但自己不持有对象:

    - (id)object {

       id obj = [[NSObject alloc] init];

       [obj autorelease];

       return obj;

    }

    使用了autorelease方法,可以使取得的对象存在,但自己不持有对象。

    release:立即释放

    autorelease:不立即释放,注册到autoreleasepool中,pool结束时自动调用release方法

    无法释放非自己持有的对象:

    id obj = [NSObject object]; // 取得的对象存在,但自己不持有对象

    [obj release]; // 释放非自己持有的对象,应用程序崩溃

    苹果采用散列表(引用计数表)来管理引用计数

    引用计数表各记录中存有内存块地址,可从各个记录追溯到各对象的内存块

    1.3 ARC规则

    id obj = [[NSObject alloc] init]; // id 和  对象类型在没有明确指定所有权修饰符时,默认为__strong修饰符 等同于 id __strong obj = [[NSObject alloc] init];

    ARC:

    {

      id __strong obj = [[NSObject alloc] init];

    }

    // 此源代码明确指定了C语言的变量的作用域

    MRC:

    {

      id obj = [[NSObject alloc] init];

      [obj release];

    }

    // 为了释放生成并持有的对象,增加了 release 方法;该源代码进行的动作同ARC的动作完全一样

    附有__strong修饰符的变量obj在超出其变量作用域时,即在该变量被废弃时,会释放其被赋予的对象

    {

      // 自己生成并持有对象

      id __strong obj = [[NSObject alloc] init];

    }

     // 因为变量obj超出其作用域,强引用失效,所以自动地释放自己持有的对象

    通过__strong 修饰符,不必再次键入retain或者release,完美地满足了“引用计数内存管理的思考方式”:

        自己生成的对象,自己所持有

        非自己生成的对象,自己也能持有

        不再需要自己持有的对象时释放

        非自己持有的对象无法释放

    @interface Test : NSObject

    {

        id __strong obj_;

    }

    - (void)setObject:(id __strong)obj;

    @end

    @implementation Test

    - (id)init

    {

       self = [super init];

       return self;

    }

    - (void)setObject:(id __strong)obj 

    {

       obj_ = obj;

    }

    @end

    循环引用:

    {

       id test0 = [[Test alloc] init]; // 对象A   test0持有Test对象A的强引用

       id test1 = [[Test alloc] init]; // 对象B   test1持有Test对象B的强引用

       [test0 setObject:test1]; // 对象A的obj_成员变量持有对象B的强引用 

       [test1 setObject:test0]; // 对象B的obj_成员变量持有对象A的强引用

    }

    // test0变量超出其作用域,强引用失效,所以自动释放对象A

    // test1变量超出其作用域,强引用失效,所以自动释放对象B

    // 此时,持有对象A的强引用的变量为  对象B的obj_ ; 持有对象B的强引用的变量为 对象A的obj_

    // 发生内存泄漏

    // 循环引用很容易发生内存泄漏 <内存泄漏就是应当废弃的对象在超出其生存周期后继续存在>

    __weak 修饰符提供弱引用,弱引用不能持有对象实例

    id __weak obj = [[NSObject alloc] init]; // 编译器对此会给出警告⚠️

    // 此源代码将自己生成并持有的对象赋值给附有__weak修饰符的变量obj。即变量obj持有对持有对象的弱引用。因此,为了不以自己持有的状态来保存自己生成并持有的对象,生成的对象会立即被释放

    id __unsafe_unretained obj = [[NSObject alloc] init]; // ⚠️

    __unsafe_unretained修饰符同__weak一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放

    __unsafe_unretained修饰的变量既不持有对象的强引用也不持有对象的弱引用

    @autoreleasepool {

        id __autoreleasing obj = [[NSObject alloc] init];

    }

  • 相关阅读:
    【转】解决IIS 用localhost需要用户名密码!
    Android monkey 资料
    monkey命令参数
    打开chrome 应用商店
    delphi PDF控件介绍
    delphi PDFium 编辑操作
    delphi PDFium介绍
    delphi使用RichView控件 表格撤消
    delphi使用RichView控件 表格编辑操作
    delphi PDFium 常用功能
  • 原文地址:https://www.cnblogs.com/yangyangyang/p/6774330.html
Copyright © 2011-2022 走看看