读书笔记 - 《Objective-C 高级编程 iOS 与 OSX 多线程与内存管理》

第 1 章 自动引用计数

1.3 ARC 规则

  • __strong 强引用 (通常非显式使用)
  • __weak 弱引用
  • __unsafe_unretained 修饰符变量的对象在通过该变量使用时,如果没有确保其确实存在(可能已经被释放为nil),应用程序就会崩溃(修饰的变量不属于编译器的内存管理对象)
  • __autoreleasing ARC 有效时,要通过将对象赋值给附加了 autoreleasing 修饰符的变量来替代调用 autorelease 方法。对象赋值给附有 autoreleasing 的变量等价于在 ARC 无效时调用对象的 autorelease 方法,即对象被注册到 autoreleasepool (通常非显式使用)
  • __bridge 转换(通过 bridge 转换显式转换 id 和 * void ,id 和 void * 就能互相转换)
  • 属性声明的属性所有权修饰符的对应关系
属性声明的属性 所有权修饰符
copy __strong (但是赋值的是被复制的对象)
retain __strong
strong __strong
unsafe_unretained __unsafe_unretained
weak __weak

1.4 ARC 的实现 (LLVM 编译器 + 运行时库)

  • 赋值给附有 __strong 修饰符的变量 id __strong obj = [[NSObject alloc] init];

      // 编译器的模拟代码  
      id obj = objc_msgSend(NSObject, @selector(alloc));  
      objc_msgSend(obj, @selector(init));  
      objc_release(obj);
    
  • [NSMuableArray array] 类方法中间会调用 objc_retainAutoreleasedReturnValue 和 objc_autoreleaseReturnValue(return 时用到) ,使得原本应注册到 autoreleasepool 中的 object 通过上述两个底层方法达到最优化。

第 2 章 Blocks

2.1 Blocks 概要

  • Blocks : 带有自动变量(局部变量)的匿名函数

2.2 Blocks 模式

  • Block 语法 : ^ (返回值类型) (参数列表) 表达式

2.3 Blocks 的实现

  • Block 存储域
    • 表1 - Block 的类
设置对象的存储域
_NSConcreteStackBlock
_NSConcreteGlobalBlock 程序的数据区域(.data 区)
_NSConcreteMallocBlock
    • 表2 - Block 的副本

Block 的类 |副本源的配置存储域 |复制效果
---------------------- | -------------
_NSConcreteStackBlock | 栈 |从栈复制到堆
_NSConcreteGlobalBlock | 程序的数据区域 |什么也不做
_NSConcreteMallocBlock | 堆 |引用计数增加

**  总结:不管 Block 配置在何处,用 copy 方法复制都不会引起任何问题。**
  • 什么时候栈上的 Block 会复制到堆?

    1. 调用 Block 的 copy 实例方法时
    2. Block 作为函数返回值返回时
    3. 将 Block 赋值给附有 __strong 修饰符 id 类型的类或 Block 类型成员变量时
    4. 在方法名中含有 usingBlock 的 Cocoa 框架方法或 GCD 的 API 中传递 Block 时
  • 在 Block 中使用附有 __strong 修饰符的 id 类型或对象类型自动变量的情况下,当 Block 从栈复制到堆时,使用 _Block_object_assign 函数,持有 Block 截获的对象。当堆上的 Block 被废弃时,使用 _Block_object_dispose 函数,释放 Block 截获的对象。在 __block 变量为附有 __strong 修饰符的 id 类型或自动类型变量的情形下也会发生同样的过程。

第 3 章 Grand Central Dispatch

3.1 GCD 概要

  • 什么是 GCD? GCD 是异步执行任务的技术之一

3.2 GCD 的 API

  • 表1 Dispatch Queue 的种类
Dispatch Queue 的种类 说明
Serial Dispatch Queue 等待现在执行中处理结束
Concurrent Dispatch Queue 不等待现在执行中处理结束
  • dispatch_queue_create -- 生成 Dispatch Queue

    1. 生成 Serial Dispatch Queue

       dispatch_queue_t mySerialDispatchQueue =  
       dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);
      
    2. 生成 Concurrent Dispatch Queue

       dispatch_queue_t myConcurrentDispatchQueue =  
       dispatch_queue_create("com.example.gcd.MyConcurrentDispatchQueue",          DISPATCH_QUEUE_CONCURRENT);     
      
    3. ARC 下通过 dispatch_queue_create 函数生成的 Dispatch Queue 在使用结束后需要通过 dispatch_release 函数释放

       dispatch_release(myDispatchQueue);
      
  • Main Dispatch Queue / Global Dispatch Queue -- 获取系统标准提供的 Dispatch Queue

    • 表2 系统提供的 Dispatch Queue 的种类

名称| Dispatch Queue 的种类 | 说明
---------------------|----
Main Dispatch Queue |Serial Dispatch Queue|主线程优先
Global Dispatch Queue (High Priority)|Concurrent Dispatch Queue| 执行优先级:高(最高优先)
Global Dispatch Queue (Default Priority)|Concurrent Dispatch Queue|执行优先级:默认
Global Dispatch Queue (Low Priority)|Concurrent Dispatch Queue|执行优先级:低
Global Dispatch Queue (Background Priority)|Concurrent Dispatch Queue|执行优先级:后台

* 获取方法  

        dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
          
        dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
          
        dispatch_queue_t globalDispatchDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
          
        dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
          
        dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
  • dispatch_set_target_queue -- 变更生成的 Dispatch Queue 的执行优先级

  • dispatch_after -- 在指定时间追加处理到 Dispatch Queue

      dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
      dispatch_after(time, dispatch_get_main_queue(), ^{
          NSLog(@"waited at least three seconds.");
      });
    
  • Dispatch Group - 监视一些处理执行的结束

      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      dispatch_group_t group = dispatch_group_create();
      
      dispatch_group_async(group, queue, ^{
          NSLog(@"block 0 ");
      });
      dispatch_group_async(group, queue, ^{
          NSLog(@"block 1 ");
      });
      dispatch_group_async(group, queue, ^{
          NSLog(@"block 2 ");
      });
      
      dispatch_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
      
      // 还有一个等待执行结束
      //dispatch_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC));
    
  • dispatch_barrier_async - 等待追加到 Concurrent Dispatch Queue 上的并行执行的处理全部结束之后,再将指定的处理追加到该 Queue 中,然后由 dispatch_barrier_async 函数追加的处理执行完毕后,Queue 才恢复为一般的动作,追加到该 Queue 的处理又开始并行执行。可以实现高效率的数据库访问和文件访问

  • dispatch_apply - 是 dispatch_sync 和 Dispatch Group 的关联 API ,等待全部处理执行结束,这样可以在 Global Dispatch Queue 中对所有元素执行 Block

      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
     dispatch_apply(10, queue, ^(size_t index) {
         NSLog(@"%zu", index);
     });
     NSLog(@"done"); 
    
  • dispatch_suspend / dispatch_resume - 挂起 Queue / 恢复 Queue

  • Dispatch Semaphore - 是持有计数的信号,该计数是多线程编程中的计数信号类型。计数为 0 时等待,计数大于等于 1 时,减去 1 而不等待。

      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      
      dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
      // Dispatch Semaphore 的计数初始值设定为 1
      // 保证可访问 NSMutableArray 类对象的线程同时只能有一个 
      
      NSMutableArray *array = [NSMutableArray array];
    
      for (int i = 0; i < 100; i++) {
          dispatch_async(queue, ^{
              // 等待 Dispatch Semaphore 
              // 直到 Dispatch Semaphore 的计数值达到大于等于 1 
              dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
              
              // 大于等于1 所以将 Dispatch Semaphore 的计数值减去 1 
              // dispatch_semaphore_wait 函数执行返回,即执行到此的 Dispatch               // Semaphore 的计数值恒为 0 ,可访问的线程只有一个,保证安全
              [array addObject:[NSNumber numberWithInt:i]];
              
              // 通过 dispatch_semaphore_signal 函数 
              // 将 Dispatch Semaphore 的计数值增加 1
              dispatch_semaphore_signal(semaphore);
          });
      }
    
  • dispatch_once - 保证应用程序执行中只执行一次指定处理的 API

  • Dispatch I/O & Dispatch Data - 使用 Global Dispatch Queue 将一个文件按某个大小 read / write , 将文件分割为一块一块地进行处理

3.3 GCD 实现

  • Dispatch Queue

    • 用于管理追加的 Block 的 C 语言层实现的 FIFO 队列
    • Automic 函数中实现的用于排他控制的轻量级信号
    • 用于管理线程的 C 语言层实现的一些容器
  • Dispatch Source - 是 BSD 系内核惯有功能 kqueue 的包装,比起 Dispatch Queue 是可以取消的

    • kqueue 是应用程序处理 XNU 内核中发生的各种事件的方法中最优秀的一种

你可能感兴趣的:(读书笔记 - 《Objective-C 高级编程 iOS 与 OSX 多线程与内存管理》)