(每天更一題)群里收集的問答式小知識:

第一題,我們常說Objective C的消息(messaging)機制,那么Objective C的消息發送和c++的函數調用區別在哪里呢?

答: 主要區別就是 c++ 在編譯期就會把函數調用轉換為具體調用的哪塊代碼,而 OC 是在運行時才去找的。所以我們才能有那么多 runtime 黑科技

第二題,SomeClass* someObject = [SomeClass new]; 這行代碼的內存分配在什么地方呢?

答: someObject 這個指針在棧區,指向的 object 在堆區啦。如果 someObject 有個 int 類型的屬性,這個屬性也是放在堆區的

第三題,我們知道最好在.m而不是.h里import,為了避免暴露過多細節、防止循環引用,加快編譯等。但有哪些情況必須在.h中引用?這些情況下要是循環引用了咋辦呢?

答:必須在 .h 中引用的情形包括繼承父類,必須引用父類的 .h;實現 protocol,必須引用 protocol 的 .h。如果造成循環引用了怎么辦呢?首先,兩個類肯定不能互相繼承,父類沒有這問題。如果是 protocol,可以把 protocol 單拿出來放到一個 .h 里,跟任何類都不在一起……

第四題,常量的命名規范是什么樣的?

答:第四題 就是一般情況放在 .m 里,用 k 開頭。但是如果要暴露在 .h 里,就要用類名做前綴了,免得重復~

第五題,咱們平常定義變量都會static const CGFloat……這樣,那不加static可以嗎?

答:加 static const,會在編譯優化的時候直接替換,跟 #define 差不多(但比 #define 有很多好處)。加 static 的好處是,可以讓這個常量的范圍限制在這個 .m 之內。如果不加 static,會在全局創建一個符號,如果有兩個重名的就該報錯啦。

第六題,假設我們為一個 enum 寫了 switch 語句,switch(someEnum) { case xx: … break; ….} 這種,如果對 enum 的每一個取值都加上了 case 來處理,那么還要寫 default 分支嗎?為啥?

答:不寫default較好。因為這樣,如果后面增加了enum選項,會立即報一個warning,讓你不會忘了處理它。一般即使不需要處理的選項,也要把它寫出來,也是同樣的原因。如果是每個分支直接return的話,最好在函數結尾加一句return。

第七題,使用enum的時候,我們經常會把幾個選項或起來。那么接收方拿到這個或起來的結果,該怎么使用呢?如何知道里面或了哪幾個選項呢?

答:與上對應的選項 if (options & SomeOption) 即可。唯一要注意的就是不要習慣性地寫 == YES。因為與出來的結果可能為二進制的 10、100 等。

第八題, 你用過@dynamic嗎?它有什么用?一般是什么情況下用的?

答: 其實這個 @dynamic 的意思就是跟系統說,不要創建 property 對應的成員變量(就是一般的 _someProperty),也不要自動生成 get/set 方法,同時不要報錯,到在運行時我自己會來添加 get/set 方法。比如像 CoreData 的對象,有些屬性并不是用 _someProperty 存起來的,而是從數據庫里讀出來的。那么就不需要系統默認的 getter、setter,而是在運行時生成~

第九題, @property (nonatomic, copy) NSMutableArray* array; 這樣寫有啥問題~ 就醬=w=

答:就是 NSMutableArray 一 copy 就會變成一個不可變的 NSArray。所以這個屬性的 setter 就會導致,實際存起來的對象是不可變的。一旦調到 NSMutableArray 特有的方法比如 addObject 等,會馬上 crash。非常危險。

第十題,如何重寫一個atomic屬性的getter,setter呢~大家自己寫寫看吧_
答:就把self鎖上就可以了~注意如果你只重寫getter或者setter就會報錯,因為如果getter或setter不能鎖住同一個東西的話就沒法實現atomic鳥。

第十一題,在現代的 Objective-C 中,我們經常使用 . 語法來訪問和修改屬性~ 比如 self.name = @"hamster"; 很少再使用下劃線的語法了。但是,請問哪些情況下必須使用下劃線語法,而不能使用點語法呢?~
答:
第一種,getter、setter 里必須用下劃線語法,原因是顯而易見的,不然會無限遞歸.
第二種,init 方法里必須用下劃線語法。這個原因好像沒有同學說,主要是因為,子類可能會重寫 setter 方法。如果 init 里用點語法,父類的 init 方法里會不留神調到子類的 setter,造成意料之外的烏龍,還可能會有危險。
第三種,dealloc 里不要用任何點語法~ 一方面還是子類父類的問題,dealloc 是 init 的逆過程,問題同理。另一方面,重寫的 getter、setter 里可能會有在 dealloc 階段來做不安全的行為,要避免觸發它們。

第十二題:我們都知道category 可以給一個類增加新的方法,尤其是系統的類,我們改變不了。那么,可以給一個系統的類增加新的屬性嗎?category 新加的方法可以使用到這些新的屬性嗎?
答:
1.雷純峰的: http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-principle 主要講解Associated Objects 的實現原理和內存管理策略
2.sunny的: http://blog.sunnyxx.com/2014/03/05/objc_category_secret/ 主要講解catogry拓展方法的實現原理
3.美團網的: http://tech.meituan.com/DiveIntoCategory.html 更深入講解category的實現原理

第十三題:大家如果看了它的API,會發現跟kvc的key object機制很像。那么,能說一說 associate object 和 kvc 機制的區別在哪里嗎?~
答:這個問題想強調的就是,associated object語法看著像key value,但實際它的key機制跟我們平常習慣的有一點不同,我們習慣的比如NSDictonary,兩個key只要isEqual方法返回YES就認為是相同的key,而associated object 的key是類似用==來判斷的,不是要求內容相同,而是指針地址必須完全一致,所以我們一般把key存到一個靜態變量里~

第十四題:當我們寫下@property時我們在寫什么?

答:1. 生成一個叫_foo的成員變量 2.聲明 foo,setFoo 兩個getter setter方法 3.默認實現這兩個方法
(1)實際上以前第1步是要手動聲明,第3步是要寫一句@synthesize的,不過現在一般情況不用寫。只有你把getter setter都重寫的情況下,編譯會報錯,就說沒有_foo這個成員變量呀?這時候你還是要寫一句@synthesize
(2)前天我問大家category怎么加property,答案是關聯對象。一位同學說,不對呀,category里可以寫@property呀?是可以,protocol里也可以。然而,這里寫的@property,相當于只有第2步,沒有第1 3步。所以,它實際上是只聲明了getter setter,而沒有真正開辟一塊存儲對象的空間,并把getter setter與這個對象綁定。相當于只掛了門牌號,沒有房子。只有手機號,沒有手機。而關聯對象做的是什么?做的是第1步。第1步做好,第2 3步你可以按自己的需要去做。第一部分就講這么多。
(3)下面講第二部分,weak strong assign copy。前三個是一組。想必大家都知道weak strong有什么區別,對于OC中的對象,有一個“引用計數”的概念。比如,我聲明了一個臨時變量,Foo* foo =new Foo(); 那么系統就生成了一個Foo對象,并用foo這個指針指向它。這時候這個對象的引用計數是多少?是1,因為foo這個指針持有它。下面我把它賦給一個strong的屬性,self.foo=foo; 現在引用計數是多少?是2。然后這個函數結束了。這時候引用計數變成多少?變成1。因為foo這個臨時變量被銷毀了,所以引用計數減一。那么,如果這個屬性不是strong,而是weak呢?self.foo=foo,仍然把這個指針的值保存在了self.foo里。只不過區別在于,引用計數不加一。所以引用計數仍然是1。那么,函數結束時發生了什么呢?像上面一樣,foo這個臨時變量銷毀時,引用計數要減一。這時候引用計數就變成了0。對象就被系統回收了。以上就是strong 和weak的區別。
(4)weak類型的屬性,在對象被回收的時候,會做一個特殊處理:把這個屬性置為nil。以后我們可以討論下這個特殊機制怎么實現的,這應該算是個比較高階的面試題。之后我們再訪問self.foo,它的值就是nil了。那么,缺了這一步會怎樣,有哪些危險呢?這種情況下,指針仍然指向那一塊內存。然而,管內存管理的哥們,并不知道這塊內存有人用。當我們使用這個屬性的值,就像刻舟求劍一樣,就像一個人坐過一次火車,下次他還去同一個站臺坐火車,然而火車開往哪個終點,很可能完全不一樣了。這種情況,非常危險,很可能引起crash。
主要原因在于,
1. 這塊內存后來又被分給了其他對象,寫上了別的數據。當我還取這個屬性時,那塊內存已面目全非,根本取不出一個完整的foo了。于是系統就果斷crash。
2. 就是相反地,別的對象已經占用了這塊空間,那么我再給這個 foo 賦值,又會把別的對象已有的數據寫壞。那么一旦用到那個對象,必定又要出問題。
3. 對象銷毀的時候,也可能會 crash。如果大家切到 MRC 模式,new 出一個對象,然后 release 兩次,就要 crash。這能解釋孫總昨天的問題,為何他寫了一個 assign 的屬性,然后 self.foo = [Foo new]; 就會 crash。而 Foo* foo = [Foo new]; self.foo = foo; 就不會 crash,因為此時局部變量 foo 還引用著這個對象,引用計數還是 1,表面還是正常的。當然這個函數結束之后,局部變量被釋放,也就進入不正常的模式了。以上能告訴我們的就是,一定不要用 assign 修飾一個對象類型,這樣很不安全。關于剛才說的引用計數,大家可能會有一個疑問,比如 Foo* foo = [Foo new]; return foo; 當我 return 的時候,局部變量 foo 不是應該銷毀嘛,那接收方怎么接到的?這又是一個比較難一點的面試題…… 我們以后可以繼續討論 O O
4.昨天我們講了 strong、weak、assign,下面我們講一下 copy ……copy 跟前面三個含義不一樣,它表示的是 setter 方法會對參數進行一次拷貝,然后再儲存起來。這里提一個小問題:既然如此,為何把這個 copy 關鍵字跟 strong、weak、assign 它們放在一組呢?為何不設計成 copy 能分別跟 strong、weak 組合呢?系統有一些常見的類可以 copy,比如 NSString、NSArray、NSDictionary。而也有一些不能,比如 UIView、UIViewController。想知道一個類能不能寫 copy,只需查看它是否實現了 NSCopying 協議.而咱們要想讓自己的類支持 copy ,也需要實現這個協議,并且實現其中唯一的方法 - copyWithZone
5.關于 copy 方法的實現,還有兩點需要注意的:1. 實現時一定要是深拷貝,不然就沒有實現 copy 的語義,讓使用者迷惑,造成意外的結果 2. 注意幾個 mutable 的類不能用 copy 修飾,這個咱們之前講過。無論是 NSArray 還是 NSMutableArray,只要 copy 出來的都是不可變的,只要 mutableCopy 出來都是可變的
6.atomic 和 nonatomic...如果不寫這兩個關鍵字,系統會默認選擇哪一個呢?在 iOS 里默認是 nonatomic,OSX 里默認是 atomic。這是因為 atomic 更安全,但耗性能。nonatomic 相反。在手機上性能比較緊張, 電腦上就可以豪爽一點,所以是這么設定的。注意兩個點:1. atomic 是否能保證線程安全?答案一定是不能。線程安全是沒有這么簡單的,需要在邏輯上按自己的需求進行限制,而 atomic 只是做了一點小小的防護而已。

第十五題:對于 NSString 這個類,判斷兩個實例相等時,==、isEqual 方法和 isEqualToString 方法有什么區別?我們平常用的時候應該用哪一個呢?

答:對于 NSString 來說,isEqual 跟 isEqualToString 的區別在于,前者還會判斷是不是同一個類。如果你能確定是兩個 string 相互比較,調用 isEqualToString 效率要高一點兒~ 就這樣---參考書),但實際isEqualToString 也會判類型,所以NSString的isEqual == isEqualToString

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • ...... 對于現在經歷著的階段,是必然還是偶然我不知道,不同程度的心得體驗是有的。喜怒無常確實綁架了生活...
    思考的呆呆閱讀 293評論 0 0
  • 越來越商業化的時代里,我們走進電影院越來越少看到這種真實的東西了。也許是生活本身太過于壓抑,我們本能的排斥這種東西...
    AM王的巡夢人閱讀 656評論 0 0
  • 一: 目標: 2017年輕松喜悅的獲得50萬的財富,亞馬遜店鋪訂單多多,生意興隆! 動機和愿景: 愿我現在及過去所...
    韓磊_fb71閱讀 163評論 0 0
  • 靜靜的一個人,呼吸著雨后濕潤的空氣, 初夏的陽光微弱的透過云層, 就像初遇的那個下午。 微風沒有吹走思念,卻仿佛拂...
    jecika閱讀 215評論 0 1