读《Objective-C高级编程..》笔记

第一章、自动引用计数

1、内存管理/引用计数

  • OC中通过引用计数来进行内存管理(其他的内存管理方式有垃圾回收等)

2、内存管理原则

  • 2.1:自己生成的对象自己持有
    • 使用 alloc new copy mutableCopy 开头的方法名生成的对象,自己持有(其中以..开头是指如:allocMyObject、newObjec、copyThis等驼峰形式的方法名,而alloccate、newer等不在此列)
  • 2.2:非自己生成的对象,自己也能持有
    • 可以通过 retain 方法来持有该对象
  • 2.3:自己持有的对象,自己释放,不是自己持有的对象,自己不用管
    • 通过上述两种方式持有的对象,不需要的时候,需要通过release方法进行释放,不是自己通过上述方法持有的对象,不能调用release方法
  • 2.4:不通过上面方法获得的对象,同时自己不持有,这时候通过autorelease 进行管理
    +(objc*) getObject {
        id obj = [[objc alloc] init];
        [obj autorelease];
        return obj;
    }
    
  • 2.5:alloc/retain/release/dealloc总结
    • 通过引用计数表(散列表),来管理对象的引用计数
    • 使用allco或者rerain后,该对象的引用计数会+1
    • 使用release 后,对象的引用计数会-1
    • 当应用计数为0的时候会调用dealloc方法,废弃对象,释放内存

3、ARC规则

  • 3.1:所有权修饰符

    • 在ARC下,OC对象都必须有所有权修饰符所修饰,这就是告诉编译器,当前对象的内存管理原则,修饰符包括:_ _strong, _ _ weak, _ _unsafe_unretain, _ _autoreleasing
      • _ _strong 为默认的修饰符,具体不详细介绍
      • _ _weak 为避免循环引用产生内存泄漏问题而产生的
      • _ _unsafe_unretain 同 _ _weak性质相同,但是_weak引用的对象在被释放后,变量会被置为nil, 而 _unsafe_unretain不会
      • _ _ autoreleasing,从内存管理的原则中我们知道,在ARC无效的时候,通过alloc new copy mutableCopy以外的方法得的对象,会通过调用autorelease方法被注册到autoreleaspool中,在ARC下用autoreleasing修饰符就是为了达到这个效果,但是同strong一样,不需要显示的声明这个修饰符,在符合情况时, 系统会自动将变量加入到autoreleaspool中的。还有一种情况是写回传:因为上面的内存管理原则,下面的代码中error获得对象非自己创建,所以需要加入到autoreleaspool中,所以需要传递autoreleasing 修饰的参数,就产生了下面的过程
     NSError * error = nil;
     NSString * string =[ [NSString alloc]initWithContentsOfURL“/path/file.text” encoding:utf8 error: &error];
     //编译器将上面的代码转换为
     NSError _ _strong * error = nil;
     NSError _ _autoreleasing * tempError = error;
     NSString * string =[ [NSString alloc]initWithContentsOfURL”/path/file.text” encoding:utf8 error: &tempError];
     error = tempError
    //error 被加入到自动释放池中,一直保持到自动释放池释放为止
    

4:修饰符的内部实现略...

第二章、Block

1:block简介及基本用法

2:Block实质

  • Block被当做一个C语言的匿名函数来处理,同时他也是一个oc类型的对象,内部有isa指针变量,至于isa是啥:
    1、When a new object is created, memory for it is allocated, and its instance variables are initialized. First among the object’s variables is a pointer to its class structure. This pointer, called isa, gives the object access to its class and, through the class, to all the classes it inherits from.
    2、isa means “is a”. Every Objective-C object (including every class) has an isa pointer. The runtime follows this pointer to determine what class an object is, so it knows what selectors the object responds to, what its super class is, what properties the object has, and so on.
  • 截获自动变量,block只截获在在内部调用的变量的值,将这些截获的变量保存在block内部结构体内

第三章、GCD

1:API

  • 1.1:Dispatch Queue

    • 开发者定义想要执行的任务,并追加到任务队列中,在下面的代码中,block内部为想要执行的任务,queue为执行任务的队列,这样该任务就能在另外的线程中执行了
      dispatch_async(queue, ^{
            //想要执行的任务
        });
    
    • Dispatch Queue分为Serial Dispatch Queue(串行)和Concurrent Dispatch Queue(并发)两种
      • Serial Dispatch Queue:串行队列中同一时间只能执行一个任务,当前任务执行完后才能执行下一个任务,在串行队列中只有一个线程,当多个线程更新同一个资源,引发资源竞技的时候可以使用串行队列。
      • Concurrent Dispatch Queue:允许多个任务在同一个时间同时进行,在并发队列中有多个线程,具体线程的个数是由系统根据当前的心痛状态及CPU核数等因素自行决定的。
      • 串行队列的任务一定是按开始的顺序结束,而并发队列的任务并不一定会按照开始的顺序而结束
    • 创建:通过GCD提供的API创建队列
        //串行
        dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.ios.queue", NULL);
        //并发
        dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.ios.apple", DISPATCH_QUEUE_CONCURRENT);
      
    • Main Dispatch Queue, Global Dispatch Queue
      • 如果不通过create进行创建,我们也可以直接用系统给我们提供的队列Main Dispatch Queue, Global Dispatch Queue。其中Main 为在主线程中执行的队列,所以他是一个串行队列,Global Dispatch Queue为在主线程外运行的并发队列,同时Global Dispatch Queue还有HIGH,DEFAULT, LOW等几个优先级别
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      
        //举例用法
        dispatch_async(global, ^{
            //do something
            dispatch_async(mainQueue, ^{
                // return mainThread, update UI
            })
        });
      
  • 1.2:dispatch_set_target_queue

    • 改变队列的优先级,通过dispatch_queue_create创建的串行或并行队列的优先级均为default,可以通过这个方法改变这个优先级
      dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("mySerialQueue", NULL);
      dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
      //将mySerialDispatchQueue的优先级由默认的default改为BACKGROUND
      dispatch_set_target_queue(mySerialDispatchQueue, global);
    

    这个方法还可以改变一些其他的属性

    • 1.3:dispatch_after

      • 一段时间后将任务追加到任务队列中去
        dispatch_time_t time =  dispatch_time(DISPATCH_TIME_NOW, 3);
        dispatch_after(time, dispatch_get_main_queue(), ^{
          //3秒后追加到主线程中的任务
      });
      

      上面的列子3秒后追加到主线程中的任务,因为主线程中的runloop大概循环时间为1/61秒,所以这个任务最慢在3+1/61秒后执行。

    • 1.4 dispatch group

      • 当有多个任务执行完成后,想做统一处理,这时候可以用串行队列,但是当有多个队列,或者是并行队列中有多个任务的时候,就需要用到 dispatch group了。
      dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      
      dispatch_group_t group = dispatch_group_create();
      dispatch_group_async(group, global, ^{
          //任务1
      });
      dispatch_group_async(group, global, ^{
          //任务2
      });
      dispatch_group_async(group, global, ^{
          //任务3
      });
      
      dispatch_group_notify(group, dispatch_get_main_queue(), ^{
          //总结任务
      });
      

      另外也可以用dispatch_group_wait 代替dispatch_group_notify,来等待任务全部结束,但是不推荐这样用

    • 1.5:dispatch_barrier_async

      • 用于在一连串并发队列中设置一个障碍,在障碍前面的任务执行完成后,执行了障碍中的任务后,才能执行障碍后的任务
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          NSLog(@"任务1");
      });
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          NSLog(@"任务2");
      });
      dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          NSLog(@"插入栅栏:执行完成任务1,2后,执行插入,在执行任务3,4");
      });
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          NSLog(@"任务3");
      });
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          NSLog(@"任务4");
      });
      
    • 1.6:dispatch_once

      • 多线程状态下,保证代码只执行一次,多在生成单例的时候使用
        + (instancetype)sharedManager {
              static Manager *sharedManager = nil;
              static dispatch_once_t onceToken;
              dispatch_once(&onceToken, ^{
                  sharedManager = [[Manager alloc] init];
             });
             return sharedManager;
         }
      
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359

推荐阅读更多精彩内容