Objective-C内存管理、block与GCD

内存管理
  • 引用计数:引用计数表维护对象的引用数
  • 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)