autorelease的具体使用方法
1. 生成并持有NSAutoreleasePool对象
2. 调用已分配对象的autorelease实例方法
3. 废弃NSAutoreleasePool对象
ARC有效时,id类型和对象类型必须加上所有权修饰符,一共有四种:
使用__weak来避免循环引用,__weak不能持有对象实例,另外在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态(空弱引用)
__unsafe_unretained是不安全的所有权修饰符,尽管ARC式的内存管理编译器的工作,但附有 __unsafe_unretained修饰符的变量不属于编译器的内存管理对象,与__weak一样,也无法持有对象
在ARC有效的情况下,必须遵守一定的规则
1. 不能使用retain/release/retainCount/autorelease
2. 不能使用NSAllocateObject/NSDeallocateObject
3. 须遵守内存管理的方法命名规则
4. 不要显式调用dealloc,不能使用[super dealloc]
5. 使用@autoreleasepool 块代替NSAutoreleasePool
6. 不能使用区域(NSZone)
7. 不对象型变量不能作为C结构的成员,除非加__unsafe_unretained
8. 显式转换”id”和”void*”, 使用__bridge, __bridge_transfer, __bridge_retained
使用__weak
id __weak obj1 = obj; 将被分解成以下代码 (模拟代码)
id obj1 = 0; objc_storeWeak(&obj1, obj); objc_storeWeak(&obj1, 0);
objc_storeWeak函数把第二个参数赋值对象的地址作为键值,将第一参数的附有__weak修饰符的变量的地址注册到weak表中(哈希表),如果第二参数为, 则把变量的地址从weak表中删除。由于一个对象可同时赋值给多个附有__weak修饰符的变量中,所以对于一个键,可注册多个变量的地址。
对象的释放过程:
objc_clear_deallocating执行动作:
独自实现引用计数的类无法使用__weak,如NSMachPort,另外当allowsWeakReference/retainWeakReference方法返回No的时候也无法使用
Block是带有自动变量(局部变量)的匿名函数
Block格式: ^返回值类型 参数列表 表达式
Block可省略返回值类型,如果表达式中有return语句就使用该返回值的类型,如果表达式中没有return语句就使用void类型。若有多个return,所有return返回值类型必须相同
如果不使用参数,Block可以省略参数列表
Blocks中表达式所截获所使用的自动变是的值,即保存该自动变量的瞬间值,因为Block表达式保存了自动变量的值,所以在执行Block语法后,即使修改Block中使用的自动变量的值也不会影响Block执行时自动变量的值。
若想在Block语法中的表达式中将值赋给在Block语法外声明的自动变量,需要在该变量前加上__block说明符。
Block的实现:^(blk)(void) = ^{printf(“Block\n”);};
struct __block_impl
{
void* isa; //block类型
int Flags; //标志
int Reserved; //保留位
void* FuncPtr; //函数指针
}
struct __main_block_desc_0
{
size_t reserved; //保留位
size_t Block_size; //Block大小
}
//如果Block使用了自动变量,则自动变量会相应的追加到该结构体中, 并在构造函数中
//进行初始化
struct __main_block_impl_0
{
struct __block_iml impl; //Block实现结构
struct __main_block_desc_0* Desc; //Block描述结构
}
//block 代码块生成一个静态函数, __cself类似于self,通过该指针可以拿到里面的自动变量
static void __main_block_func_0(struct __main_block_impl_0* __cself)
{
printf(“Block\n”);
}
int main(void)
{
//将静态函数赋值给FuncPtr函数指针
void (*blk)(void) = ((void(*)())&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA));
//调用block, 调用结构中的函数指针
((void*)(__block_impl*))((__block_impl*)blk)->FuncPtr)((__block_impl*)blk);
}
静态变量/静态全局变量/全局变量 可在Block中直接修改,静态变量则是使用其指针对其进行访问
为什么自动变量不通过指针来访问?
答: 在由Block语法生成的值Block上,可以存有超过其变量作用域的被截获对象的自动变量。变量作用域结束的同时,原来的自动变量被废弃,所以Block中超过变量作用域而存在的变量同静态变量一样,不能通过指针访问原来的自动变量。通俗的说,就是Block无法确定在何时被调用,如果通过指针指向,那么当自动变量销毁之后再进行访问,将导致程序崩溃。
Block的三种类型
类型 | 设置对象的存储域 | 复制效果 |
---|---|---|
NSConcreteStackBlock | 栈 | 从栈复制到堆 |
NSConcreteGlobalBlock | 程序的数据区域 | 什么也不做 |
NSConcreteMallocBlock | 堆 | 引用计数增加 |
不管Block配置在何处,使用copy方法复制都不会引起任何问题,在不确定时调用copy方法即可。
Block提供了将Block和__block变量从栈上复制到堆上的方法
栈上的Block复制到堆上的情况:
使用__block变量避免循环引用的优点:
Dispatch Queue的种类 | 说明 |
---|---|
Serial Dispatch Queue(串行) | 等待现在执行处理结束 |
Concurrent Dispatch Queue(并形) | 不等待现在执行处理结束 |
创建Dispatch Queue的方法
1. dispatch_queue_create (DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT),通过该方法生成的queue,需要调用dispatch_release来释放
2. 获取系统标准提供的Main Dispatch Queue/Global Dispatch Queue
变更生成的Dispatch Queue的优先级应使用dispatch_set_target_queue
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create(“com.exmaple.gcd.MySerialDispatchQueue”, NULL);
dispatch_queue_t globalDispatchQueueBackground = dispach_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
dispatch_set_target_queue无法指定Main Dispatch Queue和Global Dispatch Queue
dispatch_after函数并不是在指定时间后执行处理,而是在指定时间后追加处理到Dispatch Queue.
在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,若只使用Serial Dispatch Queue,只需将处理追加到最后即可,若是使用Concurrent Dispatch Queue或同时使用多个DispatchQueue时,则需使用Dispatch Group
dispatch_group_wait等待Dispatch Group中所有处理结束,若第二个参数设置为DISPATCH_TIME_FOREVER,则将永远等待。即只要属于Dispatch Group的处理尚未结束,就会一直等待,中途不能取消,若该函数返回值为0,表示所有处理执行结束,否则表示Dispatch Group中仍有处理未执行完毕
dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue上的并行执行的处理全部结束之后,再将指定的处理追加到该Concurrent Dispatch Queue中,然后再由dispatch_barrier_async函数追加的处理执行完毕后,再Concurrent Dispatch Queue才恢复为一般的动作.
dispatch_sync函数不建议使用,因为使用该函数容易引起死锁
dispatch_apply按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理结束
dispatch_suspend/dispatch_resume 挂起/恢复指定的Dispatch Queue
Dispatch Semaphore 是持有计数的信号量,该计数是多线程编程中的计数类型信号,通过dispatch_semaphore_create创建,dispatch_semaphore_wait函数等待Dispatch Semaphore的计数值>= 1,然后计数值-1,并从dispatch_semaphore_wait函数返回,使用dispatch_semaphhore_signal可将计数值+1
dispatch_once函数是保证在应用程序执行中只执行一次指定的处理
Dispatch Source的种类
名称 | 内容 |
---|---|
DISPATCH_SOURCE_TYPE_DATA_ADD | 变量增加 |
DISPATCH_SOURCE_TYPE_DATA_OR | 变量OR |
DISPATCH_SOURCE_TYPE_MACH_SEND | MACH端口发送 |
DISPATCH_SOURCE_TYPE_MACH_RECV | MACH端口接收 |
DISPATCH_SOURCE_TYPE_PROC | 检测到与进程相关的事件 |
DISPATCH_SOURCE_TYPE_READ | 可读取文件映像 |
DISPATCH_SOURCE_TYPE_WRITE | 可写入文件映像 |
DISPATCH_SOURCE_SIGNAL | 接收信号 |
DISPATCH_SOURCE_TYPE_TIMER | 定时器 |
DISPATCH_SOURCE_TYPE_VNODE | 文件系统有变更 |
Dispatch Queue没有“取消”这一概念,一旦将处理追加到Dispatch Queue中,就没有方法可以将该处理去除,也没有方法可以在执行中取消该处理,即要么放弃取消,要么使用其他方法.
Dispatch Source可以取消, 而且取消时必须执行的处理可指定为回调用的Block形式.