iOS知識(shí)原理篇二

lldb(gdb)常用的調(diào)試命令?

  • po:打印對(duì)象,會(huì)調(diào)用對(duì)象description方法。是print-object的簡(jiǎn)寫
  • expr:可以在調(diào)試時(shí)動(dòng)態(tài)執(zhí)行指定表達(dá)式,并將結(jié)果打印出來,很有用的命令
  • print:也是打印命令,需要指定類型
  • bt:打印調(diào)用堆棧,是thread backtrace的簡(jiǎn)寫,加all可打印所有thread的堆棧
  • br l:是breakpoint list的簡(jiǎn)寫

BAD_ACCESS在什么情況下出現(xiàn)?

  • 訪問一個(gè)僵尸對(duì)象,訪問僵尸對(duì)象的成員變量或者向其發(fā)消息
  • 死循環(huán)

如何調(diào)試BAD_ACCESS錯(cuò)誤

  • 設(shè)置全局?jǐn)帱c(diǎn)快速定位問題代碼所在行
  • 開啟僵尸對(duì)象調(diào)試功能



簡(jiǎn)述下Objective-C中調(diào)用方法的過程(runtime)

  • Objective-C是動(dòng)態(tài)語(yǔ)言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector),整個(gè)過程介紹如下:
    • objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類
    • 然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行
    • 如果,在最頂層的父類(一般也就NSObject)中依然找不到相應(yīng)的方法時(shí),程序在運(yùn)行時(shí)會(huì)掛掉并拋出異常unrecognized selector sent to XXX
    • 但是在這之前,objc的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì),這三次拯救程序奔潰的說明見問題《什么時(shí)候會(huì)報(bào)unrecognized selector的異?!分械恼f明
  • 補(bǔ)充說明:Runtime 鑄就了Objective-C 是動(dòng)態(tài)語(yǔ)言的特性,使得C語(yǔ)言具備了面向?qū)ο蟮奶匦?,在程序運(yùn)行期創(chuàng)建,檢查,修改類、對(duì)象及其對(duì)應(yīng)的方法,這些操作都可以使用runtime中的對(duì)應(yīng)方法實(shí)現(xiàn)。

什么是method swizzling(俗稱黑魔法)

  • 簡(jiǎn)單說就是進(jìn)行方法交換
  • 在Objective-C中調(diào)用一個(gè)方法,其實(shí)是向一個(gè)對(duì)象發(fā)送消息,查找消息的唯一依據(jù)是selector的名字。利用Objective-C的動(dòng)態(tài)特性,可以實(shí)現(xiàn)在運(yùn)行時(shí)偷換selector對(duì)應(yīng)的方法實(shí)現(xiàn),達(dá)到給方法掛鉤的目的
  • 每個(gè)類都有一個(gè)方法列表,存放著方法的名字和方法實(shí)現(xiàn)的映射關(guān)系,selector的本質(zhì)其實(shí)就是方法名,IMP有點(diǎn)類似函數(shù)指針,指向具體的Method實(shí)現(xiàn),通過selector就可以找到對(duì)應(yīng)的IMP


  • 交換方法的幾種實(shí)現(xiàn)方式
    • 利用 method_exchangeImplementations 交換兩個(gè)方法的實(shí)現(xiàn)
    • 利用 class_replaceMethod 替換方法的實(shí)現(xiàn)
    • 利用 method_setImplementation 來直接設(shè)置某個(gè)方法的IMP


objc中向一個(gè)nil對(duì)象發(fā)送消息將會(huì)發(fā)生什么?

  • 在Objective-C中向nil發(fā)送消息是完全有效的——只是在運(yùn)行時(shí)不會(huì)有任何作用

    • 如果一個(gè)方法返回值是一個(gè)對(duì)象,那么發(fā)送給nil的消息將返回0(nil)
    • 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*)
    • float,double,long double 或者long long的整型標(biāo)量,發(fā)送給nil的消息將返回0
    • 如果方法返回值為結(jié)構(gòu)體,發(fā)送給nil的消息將返回0。結(jié)構(gòu)體中各個(gè)字段的值將都是0
    • 如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的
  • 具體原因分析

    • objc是動(dòng)態(tài)語(yǔ)言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector)
    • 為了方便理解這個(gè)內(nèi)容,還是貼一個(gè)objc的源代碼
    struct objc_class
    {
      // isa指針指向Meta Class,因?yàn)镺bjc的類的本身也是一個(gè)Object,
      // 為了處理這個(gè)關(guān)系,runtime就創(chuàng)造了Meta Class,
      // 當(dāng)給類發(fā)送[NSObject alloc]這樣消息時(shí),實(shí)際上是把這個(gè)消息發(fā)給了Class Object
      Class isa OBJC_ISA_AVAILABILITY;
      #if !__OBJC2__
      Class super_class OBJC2_UNAVAILABLE; // 父類
      const char *name OBJC2_UNAVAILABLE; // 類名
      long version OBJC2_UNAVAILABLE; // 類的版本信息,默認(rèn)為0
      long info OBJC2_UNAVAILABLE; // 類信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
      long instance_size OBJC2_UNAVAILABLE; // 該類的實(shí)例變量大小
      struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表
      struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
      // 方法緩存,對(duì)象接到一個(gè)消息會(huì)根據(jù)isa指針查找消息對(duì)象,
      // 這時(shí)會(huì)在method Lists中遍歷,
      // 如果cache了,常用的方法調(diào)用時(shí)就能夠提高調(diào)用的效率。
      // 這個(gè)方法緩存只存在一份,不是每個(gè)類的實(shí)例對(duì)象都有一個(gè)方法緩存
      // 子類會(huì)在自己的方法緩存中緩存父類的方法,父類在自己的方法緩存中也會(huì)緩存自己的方法,而不是說子類就不緩存父類方法了
      struct objc_cache *cache OBJC2_UNAVAILABLE;
      struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
      #endif
      } OBJC2_UNAVAILABLE;
    
    • objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行,然后再發(fā)送消息的時(shí)候,objc_msgSend方法不會(huì)返回值,所謂的返回內(nèi)容都是具體調(diào)用時(shí)執(zhí)行的。
    • 如果向一個(gè)nil對(duì)象發(fā)送消息,首先在尋找對(duì)象的isa指針時(shí)就是0地址返回了,所以不會(huì)出現(xiàn)任何錯(cuò)誤

objc中向一個(gè)對(duì)象發(fā)送消息[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系?

  • [obj foo];在objc動(dòng)態(tài)編譯時(shí),會(huì)被轉(zhuǎn)意為:objc_msgSend(obj, @selector(foo));

什么時(shí)候會(huì)報(bào)unrecognized selector的異常?

  • 當(dāng)調(diào)用該對(duì)象上某個(gè)方法,而該對(duì)象上沒有實(shí)現(xiàn)這個(gè)方法的時(shí)候, 可以通過“消息轉(zhuǎn)發(fā)”進(jìn)行解決,如果還是不行就會(huì)報(bào)unrecognized selector異常

  • objc是動(dòng)態(tài)語(yǔ)言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector),整個(gè)過程介紹如下:

    • objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類
    • 然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行
    • 如果,在最頂層的父類中依然找不到相應(yīng)的方法時(shí),程序在運(yùn)行時(shí)會(huì)掛掉并拋出異常unrecognized selector sent to XXX 。但是在這之前,objc的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì)
  • 三次拯救程序崩潰的機(jī)會(huì)

    • Method resolution
      • objc運(yùn)行時(shí)會(huì)調(diào)用+resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機(jī)會(huì)提供一個(gè)函數(shù)實(shí)現(xiàn)。
      • 如果你添加了函數(shù)并返回 YES,那運(yùn)行時(shí)系統(tǒng)就會(huì)重新啟動(dòng)一次消息發(fā)送的過程
      • 如果 resolve 方法返回 NO ,運(yùn)行時(shí)就會(huì)移到下一步,消息轉(zhuǎn)發(fā)
    • Fast forwarding
      • 如果目標(biāo)對(duì)象實(shí)現(xiàn)了-forwardingTargetForSelector:,Runtime 這時(shí)就會(huì)調(diào)用這個(gè)方法,給你把這個(gè)消息轉(zhuǎn)發(fā)給其他對(duì)象的機(jī)會(huì)
      • 只要這個(gè)方法返回的不是nil和self,整個(gè)消息發(fā)送的過程就會(huì)被重啟,當(dāng)然發(fā)送的對(duì)象會(huì)變成你返回的那個(gè)對(duì)象。
      • 否則,就會(huì)繼續(xù)Normal Fowarding。
      • 這里叫Fast,只是為了區(qū)別下一步的轉(zhuǎn)發(fā)機(jī)制。因?yàn)檫@一步不會(huì)創(chuàng)建任何新的對(duì)象,但Normal forwarding轉(zhuǎn)發(fā)會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象,相對(duì)Normal forwarding轉(zhuǎn)發(fā)更快點(diǎn),所以這里叫Fast forwarding
    • Normal forwarding
      • 這一步是Runtime最后一次給你挽救的機(jī)會(huì)。
      • 首先它會(huì)發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。
      • 如果-methodSignatureForSelector:返回nil,Runtime則會(huì)發(fā)出-doesNotRecognizeSelector:消息,程序這時(shí)也就掛掉了。
      • 如果返回了一個(gè)函數(shù)簽名,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象并發(fā)送-forwardInvocation:消息給目標(biāo)對(duì)象

HTTP協(xié)議中POST方法和GET方法有那些區(qū)別?

  • GET用于向服務(wù)器請(qǐng)求數(shù)據(jù),POST用于提交數(shù)據(jù)
  • GET請(qǐng)求,請(qǐng)求參數(shù)拼接形式暴露在地址欄,而POST請(qǐng)求參數(shù)則放在請(qǐng)求體里面,因此GET請(qǐng)求不適合用于驗(yàn)證密碼等操作
  • GET請(qǐng)求的URL有長(zhǎng)度限制,POST請(qǐng)求不會(huì)有長(zhǎng)度限制

使用block時(shí)什么情況會(huì)發(fā)生引用循環(huán),如何解決?

在block內(nèi)如何修改block外部變量?

使用系統(tǒng)的某些block api(如UIView的block版本寫動(dòng)畫時(shí)),是否也考慮循環(huán)引用問題?

  • 系統(tǒng)的某些block api中,UIView的block版本寫動(dòng)畫時(shí)不需要考慮,但也有一些api 需要考慮
  • 以下這些使用方式不會(huì)引起循環(huán)引用的問題
[UIView animateWithDuration:duration animations:^
{ [self.superview layoutIfNeeded]; }];

[[NSOperationQueue mainQueue] addOperationWithBlock:^
{ self.someProperty = xyz; }];

[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
            object:nil
             queue:[NSOperationQueue mainQueue]
        usingBlock:^(NSNotification * notification)
        { self.someProperty = xyz; }];
  • 但如果方法中的一些參數(shù)是 成員變量,那么可以造成循環(huán)引用,如 GCD 、NSNotificationCenter調(diào)用就要小心一點(diǎn),比如 GCD 內(nèi)部如果引用了 self,而且 GCD 的參數(shù)是 成員變量,則要考慮到循環(huán)引用,舉例如下:

    • GCD
      • 分析:self-->_operationsQueue-->block-->self形成閉環(huán),就造成了循環(huán)引用
    __weak __typeof__(self) weakSelf = self;
    dispatch_group_async(_operationsGroup, _operationsQueue, ^
    {
        [weakSelf doSomething];
        [weakSelf doSomethingElse];
    } );
    
    • NSNotificationCenter
      • 分析:self-->_observer-->block-->self形成閉環(huán),就造成了循環(huán)引用
      __weak __typeof__(self) weakSelf = self;
      _observer = [[NSNotificationCenter defaultCenter]
      addObserverForName:@"testKey"
      object:nil
      queue:nil
      usingBlock:^(NSNotification *note){
          [weakSelf dismissModalViewControllerAnimated:YES];
      }];
    

OC中常見的循環(huán)引用總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,084評(píng)論 0 9
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 892評(píng)論 0 1
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 841評(píng)論 0 2
  • 清明三天的小長(zhǎng)假,確確實(shí)實(shí)是體驗(yàn)了一把人生只有吃飯,睡覺,在路上的日子,用東北話來說,就是太得勁了。 之所以此次旅...
    吳小魚閱讀 400評(píng)論 6 30
  • 這兩天收獲寫作方面的技巧,還會(huì)不斷更新。 避免使用 “思想動(dòng)詞” 小說里的常用技巧。 思想動(dòng)詞包括:想、知道、理解...
    4t0m2閱讀 577評(píng)論 1 11

友情鏈接更多精彩內(nèi)容