1.如何實現一個線程安全的NSMutableArray?
NSMutableArray是線程不安全的,當有多個線程同時對數組進行操作的時候,可能會導致崩潰或者數據錯誤。
實現方案:
- 線程鎖:使用線程鎖對數組的讀寫操作進行加鎖;
- 派發隊列:使用“串行同步隊列”(serial synchronization queue),將讀取操作及寫入操作都安排在同一個隊列裏,即可保證數據同步。而通過併發隊列,結合GCD的柵欄塊(barrier)來不僅實現數據同步線程安全,還比串行同步隊列方式更高效。
2.id和instanceType有什麼區別
相同點:instanceType 和id 都是萬能指針,指向任意對象;
不同點:1.id在編譯時不能判斷對象的真實類型,instanceType在編譯的時候,可以判斷對象的真實類型;2.id可以用來定義變量,可以作爲返回值類型,可以作爲行參類型,instanceType只能作爲返回值類型。
3.setNeedsDisplay和layoutIfNeeded兩者有什麼關係?
UIView的setNeedsDisplay和setNeedsLayout兩個方法都是異步執行的。而setNeedsDisplay會自動調用drawrect方法,這樣可以拿到UIGraphicsGetCurrentContext進行繪製;而setNeedsLayout會默認調用layoutSubviews,給當前的視圖做了標記;layoutfNeeded查找是否有標記,如果有標記會立即刷新。
只有setNeedsLayout和layoutIfNeeded這二者結合起來使用,纔會起到立即刷新的效果。
4.@property的本質是什麼?ivar、getter、setter是如何生成並添加到類中的?
- @property的本質是實例變量(ivar)+存取方法(getter、setter),即@property = ivar+ getter + setter;
"屬性"(property)作爲OC的一項特性,主要作用在於封裝對象中的數據。OC對象通常會把期所需要的書就保存爲各種實例變量。實例變量一般通過存取方法來訪問,其中,getter方法用於讀取變量值,setter方法用戶寫入變量值。
- ivar、getter、setter是自動合成到類中的。
完成屬性定義後,編譯器會自動編寫訪問這些屬性所需要的方法,這個過程叫做“自動合成”。需要強調的是,這個過程由編譯器在編譯期完成,所以你編輯器裏面看不到這些合成源代碼。除了生成方法代碼getter、setter之外,編譯器還要自動向類中添加適當類型的實例變量,並在屬性名前加上下劃線_,以此作爲實例變量的名字。也可以在類的實現代碼裏通過@synthesize語法來指定實例變量的名字。
5.iOS內存分區情況
- 棧區(Stack):
由編譯器自動分配和釋放,存放函數的參數、局部變量的值等;棧是向低地址擴展的數據結構,是一塊連續的存儲區域
- 堆區(Heap):
由程序員分配和釋放,是向高地址擴展的數據結構,是一個不連續的內存區域。
- 全局區:
全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量是在一塊區域,未初始化的全局變量和靜態變量是在相鄰 的另一塊區域。
- 常量區:
存放常量字符串,程序結束後由系統釋放。
- 代碼區:
存放函數體的二進制代碼
- 注:
(1)在 iOS中,堆區的內存是應用程序共享的,堆中的內存分配是由系統負責的。
(2)系統使用一個鏈表來爲維護所有已經分配的內存空間(系統僅僅記錄,比ing不管理具體的內容)
(3)變量使用結束後,需要釋放內存,OC中判斷引用計數是否爲0,如果是0就說明沒有任何變量使用該空間,那麼系統將其回收。
(4)當一個APP啓動後,代碼區、常量區、全局區的大小就已經固定,因此指向這些區的指針不會產生崩潰性錯誤。而堆區和棧區是時刻變化的(堆的創建銷燬,棧的入棧出棧),所以當一個指針指向這個區裏的內存時,一定要注意內存是否已經被釋放,否則會產生程序崩潰(野指針)。