美文网首页
Objective-C内存管理、block与GCD

Objective-C内存管理、block与GCD

作者: hellorob | 来源:发表于2018-06-24 17:16 被阅读0次
    内存管理
    • 引用计数:引用计数表维护对象的引用数
    • autorelease:添加到最内层的AutoReleasePool对象列表,在销毁AutoReleasePool时释放列表内对象
    1. 非alloc/new/copy/mutableCopy开始的方法返回的对象,自动注册到autoreleasepool,但是如果返回值被强应用,则编译器会优化为不需要注册到autoreleasepool。
    2. 对象指针的指针,默认指向的对象为__autorealease,因为原则上非自己创建的对象不应由自己持有。如NSError **等价于 NSError * __autorelease *
    • ARC使用规则
    1. 不能使用retain/release/retainCount/autorelease
    2. 不能使用NSAllocateObject/NSDeallocateObject
    3. 必须遵守内存管理方法的命名规则

    alloc/new/copy/mutableCopy开头的方法必须返回对象
    init开头的方法要求更严格,必须是实例方法,返回的对象必须是id、所在的类、该类的超类或子类。返回的对象不会注册到autoreleasepool。

    1. 不要显示调用dealloc
    2. 使用@autoreleasepool代替NSReleasePool

    MRC也应该用@autoreleasepool

    1. 不能使用NSZone

    MRC也不要用,其实系统会忽略

    1. 对象变量不能作为C语言结构体成员

    C语言没法管理结构体上的成员的生命周期

    1. 需要显示转换id和void *

    __bridge转换,不发生所有权的转换
    __bridge_retained,转换后的变量也持有对象
    __bridge_transfer,被转换的变量所持有的对象赋值给目标变量后释放
    对应Core Foundation的转换CFBridgingRetain/CFBridgingRelease

    void *p = (__bridge_retained void *) obj;
    id obj = (__bridge_transfer id) p;
    
    • 属性@property
      assign/copy/retain/strong/unsafe_unretained/weak

    在生命类成员变量时,和属性声明的不一样时会有编译错误,当然现在一般也不需要手动写生成类成员变量,一般都是直接用@property自动生成。

    • ARC实现
      1 . strong,在作用域结束时release,对于非alloc/init/copy方法的对象,本来是通过objc_autoreleaseReturnValue(obj)注册到autoreleasepool,但是在被strong引用时,会通过调用objc_retainAutorealseReturnValue(obj)来引用对象,这时编译器就判断为不需要添加到autoreleasepool。
    1. weak,引用对象时记录到weak表中,在对象释放时,吧weak表中指向对象的变量置空。使用weak变量时会自动生成临时变量,对象被添加到autorealeasepool。
    id __weak o = obj;
    NSLog(@"1 %@", obj);   // 添加一次
    NSLog(@"2 %@", obj);   // 再添加一次
    
    // 改为下面可以避免添加到autoreleasepool
    id __weak o = obj;
    id tmp = o;
    NSLog(@"1 %@", tmp);  
    NSLog(@"2 %@", tmp);   
    

    3、autorealease,相当于MRC的手动调用autorealease方法

    Blocks

    Blocks是C语言的扩展功能:带有自动变量的匿名函数。
    格式:

    ^int (int count) {return count + 1;}  // 完整格式
    ^(int count) {printf("%d", count)} // 无返回值
    ^{printf("test")} // 无返回值
    // block类型定义
    typedef int (^blk_t) (int);
    
    • 截获自动变量

    普通变量的值未截获时的值,不能修改
    __block变量可以被block修改值
    不支持截获数组,需要的话转为指针

    • block的实现

    block实质上是会生成一个Objective-C的对象,截获的自动变量会保存在对象中,__block变量会生成__Block_byrefer_val结构体,存放到block中,通过其中的__forwarding间接访问实际变量,当block被复制到堆时,如果栈上的__block变量也会被复制到堆。

    • 有三种区域的block
      全局Block:在全局变量处定义或者在Block不需要截获自动变量时
      栈Block:除全局Block之外,定义时默认都是栈Block
      堆Block:Block作为函数返回值时会被复制到堆,使用copy方法会复制到堆,将Block赋值给strong类型的变量,或者赋值给Block类型的成员变量时会复制到堆。

    向方法传递Block时不会自动复制到堆,除了下面两种方法:

    1. Cocoa框架中代用usingBlock的方法
    2. GCD的API
      对全局Block进行copy没有任何作用
    • block循环应用
    1. 通过__weak解决
    2. MRC时通过__block解决,但是需要在Block执行完后置空,在置空之后才会释放。这是因为__block指向的对象复制到堆时不会被retain。
    GCD
    • 两种队列:Serial DispatchQueue和Concurrent Dispatch Queue

    一个Serial Dispatch Queue生成并使用时会创建一个新线程,需要防止过多线程
    Dispatch Queue必须自己release,并且对于非create方法返回的queue要retain

    • dispatch_set_target_queue
    1. 变更队列的执行优先级
    2. 目标队列可以成为原队列的执行阶层(多个queue被设置到某个target时)
    • dispatch_after

    并不是在指定的时间后执行,二是在指定的时间后添加到queue

    • Dispatch Group

    在希望多个处理全部执行之后,再执行其他处理时使用

    • dispatch_barrier_async

    等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行

    • dispatch_async

    在处理执行结束之前,函数不会返回。注意死锁问题,如下:

    dispatch_queue_t queue dispatch_get_main_queue();
    dispatch_async(queue, ^{
            dispatch_sync(queue, ^{});
    })
    
    • dispatch_apply

    按指定次数讲block追加到指定的queue中并等待处理完毕。

    • dispatch_suspend / dispatch_resume

    暂停或恢复queue对执行的处理,对于已处理或正在处理的没有影响

    • Dispatch Semaphore

    信号量,wait方法计数未0时等待,计数>=1时不等待而减去1。signal方法加1

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); // 创建数量为2的信号量
    dispatch_semaphore_wait(semaphore, time); // 信号量-1
    dispatch_semaphore_signal(semaphore); // 信号量+1
    
    
    • dispatch_once

    保证应用程序执行过程中只执行一次处理

    相关文章

      网友评论

          本文标题:Objective-C内存管理、block与GCD

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