Q:ARC下,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些劳殖?
對應基本數(shù)據(jù)類型默認關鍵字是:atomic,readwrite,assign
對于普通的 Objective-C 對象:atomic,readwrite,strong
Q:atomic 修飾的屬性是怎么樣保存線程安全的桃犬?
答:編譯器會自動生成互斥鎖,對 setter 和 getter 方法進行加鎖,可以保證屬性的賦值和取值原子性操作是線程安全的,但不包括操作和訪問。
比如說atomic修飾的是一個數(shù)組的話维咸,那么我們對數(shù)組進行賦值和取值是可以保證線程安全的。但是如果我們對數(shù)組進行操作惠爽,比如說給數(shù)組添加對象或者移除對象癌蓖,是不在atomic的負責范圍之內的,所以給被atomic修飾的數(shù)組添加對象或者移除對象是沒辦法保證線程安全的疆股。
Q:什么情況使用 weak 關鍵字费坊,相比 assign 有什么不同?
答:
在 ARC 中旬痹,在有可能出現(xiàn)循環(huán)引用的時候附井,往往要通過讓其中一端使用 weak 來解決讨越,比如: delegate、block永毅。
自身已經(jīng)對它進行一次強引用把跨,沒有必要再強引用一次,此時也會使用 weak沼死,自定義 IBOutlet 控件屬性一般也使用 weak着逐,使用 storyboard(xib 不行)創(chuàng)建的 vc,會有一個叫 _topLevelObjectsToKeepAliveFromStoryboard 的私有數(shù)組強引用所有 top level 的對象意蛀,所以這時即便 outlet 聲明成 weak 也沒關系耸别。當然,也可以使用 strong县钥。
weak 和 assign 的不同點:
① weak只能修飾對象秀姐,而assign既可以修飾對象也可以修飾基本數(shù)據(jù)類型;
② assign修飾的對象在被釋放后若贮,指針仍然指向原對象地址省有;而weak修飾的對象在被釋放之后會自動置指針為 nil;
③ 相同點:在修飾對象的時候谴麦,assign和weak都不改變對象的引用計數(shù)蠢沿。
Q:weak修飾的釋放則自動被置為nil的實現(xiàn)原理
答:weak 實現(xiàn)原理的概括:
Runtime維護了一個weak表,用于存儲指向某個對象的所有weak指針匾效。weak表其實是一個hash(哈希)表舷蟀,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象的地址)數(shù)組弧轧。
weak 的實現(xiàn)原理可以概括一下三步:
1雪侥、初始化時:runtime會調用objc_initWeak函數(shù)碗殷,初始化一個新的weak指針指向對象的地址精绎。
2、添加引用時:objc_initWeak函數(shù)會調用 objc_storeWeak() 函數(shù)锌妻, objc_storeWeak() 的作用是更新指針指向代乃,創(chuàng)建對應的弱引用表。
3仿粹、釋放時搁吓,調用clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組吭历,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設為nil堕仔,最后把這個entry從weak表中刪除,最后清理對象的記錄晌区。
Q:為什么iOS開發(fā)中摩骨,控件一般為weak而不是strong?
IBOutlet的屬性一般可以設為weak是因為它已經(jīng)被view引用了通贞,除非view被釋放,否則IBOutlet的屬性也不會被釋放恼五,另外IBOutlet屬性的生命周期和view應該是一致的昌罩,所以IBOutlet屬性一般設為weak。
簡單的說灾馒,如果IBOutlet對象是nib/xib scene的擁有者(File’s owner)所持有的對象茎用,那么很顯然擁有者必須“擁有”對象的指針,因此屬性應設置為strong睬罗。而其他的IBOutlet對象的屬性需要設置為weak轨功,因為擁有者并不需要“擁有”他們的指針。
答:因為view被添加到superView上面后容达,就被superView持有了夯辖。我們一般在IB里面的拖的view都是加在了根view或者它的子view上。而根view又被它的controller持有董饰,所以IBOutlet可以用weak蒿褂。如果,在IB里面拖出來的view是一個單獨的view沒有被加到任何其他view上卒暂,則需要用strong啄栓。
Q:以下代碼會出現(xiàn)什么問題?(深淺拷貝)
@property (copy) NSMutableArray *array;
答:
1.把NSMutableArray用copy修飾有時就會crash也祠,因為對這個數(shù)組進行了增刪改操作昙楚,而copy后的數(shù)組變成了不可變數(shù)組NSArray,沒有響應的增刪改方法诈嘿,所以對其進行增刪改操作就會報錯堪旧。
2.默認atomic修飾,編譯器會自動生成互斥鎖奖亚,對 setter 和 getter 方法進行加鎖操作淳梦,這個過程會消耗一些性能,執(zhí)行效率慢,一般使用nonatomic修飾
Q:用@property聲明的NSString(或NSArray昔字,NSDictionary)經(jīng)常使用copy關鍵字爆袍,為什么?如果改用strong關鍵字作郭,可能造成什么問題陨囊?
1.因為父類指針可以指向子類對象,使用 copy 的目的是為了讓本對象的屬性不受外界影響,使用 copy 無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.
2.如果我們使用是 strong ,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.
copy 此特質所表達的所屬關系與 strong 類似。然而設置方法并不保留新值夹攒,而是將其“拷貝” (copy)蜘醋。
Q:@property 的本質是什么?ivar咏尝、getter压语、setter 是如何生成并添加到這個類中的闲先?
@property的本質是 ivar(實例變量) + getter + setter.
attributes的具體內容包含: 類型, 原子性, 內存語義和對應的實例變量.
我們每次在增加一個屬性, 系統(tǒng)都會在 ivar_list 中添加一個成員變量的描述, 在 method_list 中增加 setter 與 getter 方法的描述, 在屬性列表中增加一個屬性的描述, 然后計算該屬性在對象中的偏移量, 然后給出 setter 與 getter 方法對應的實現(xiàn), 在 setter 方法中從偏移量的位置開始賦值, 在 getter 方法中從偏移量開始取值, 為了能夠讀取正確字節(jié)數(shù), 系統(tǒng)對象偏移量的指針類型進行了類型強轉.
Q:weak屬性需要在dealloc中置nil么?
不需要无蜂。
在ARC環(huán)境無論是強指針還是弱指針都無需在 dealloc 設置為 nil 伺糠, ARC 會自動幫我們處理
即便是編譯器不幫我們做這些,weak也不需要在 dealloc 中置nil:因為在屬性所指的對象遭到摧毀時斥季,屬性值也會清空(nil out)训桶。
當一個被weak修飾的對象被釋放后,weak對象怎么處理的酣倾?
清除weak變量舵揭,同時設置指向為nil。當對象被dealloc釋放后躁锡,在dealloc的內部實現(xiàn)中午绳,會調用弱引用清除的相關函數(shù),會根據(jù)當前對象指針查找弱引用表映之,找到當前對象所對應的弱引用數(shù)組拦焚,將數(shù)組中的所有弱引用指針都置為nil。
Q:說說你理解weak屬性杠输?
Runtime維護了一個weak表赎败,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash(哈希)表蠢甲,Key是所指對象的地址僵刮,Value是weak指針的地址(這個地址的值是所指對象的地址)數(shù)組。
1鹦牛、初始化時:runtime會調用objc_initWeak函數(shù)搞糕,初始化一個新的weak指針指向對象的地址。
2曼追、添加引用時:objc_initWeak函數(shù)會調用 objc_storeWeak() 函數(shù)窍仰, objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對應的弱引用表拉鹃。
3辈赋、釋放時,調用clearDeallocating函數(shù)膏燕。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設為nil悟民,最后把這個entry從weak表中刪除坝辫,最后清理對象的記錄。
追問的問題一:
1.實現(xiàn)weak后射亏,為什么對象釋放后會自動為nil近忙?
runtime 對注冊的類竭业, 會進行布局,對于 weak 對象會放入一個 hash 表中及舍。 用 weak 指向的對象內存地址作為 key未辆,當此對象的引用計數(shù)為 0 的時候會 dealloc,假如 weak 指向的對象內存地址是 a 锯玛,那么就會以 a 為鍵咐柜, 在這個 weak 表中搜索,找到所有以 a 為鍵的 weak 對象攘残,從而設置為 nil 拙友。
追問的問題二:
2.當weak引用指向的對象被釋放時,又是如何去處理weak指針的呢歼郭?
1遗契、調用objc_release
2、因為對象的引用計數(shù)為0病曾,所以執(zhí)行dealloc
3牍蜂、在dealloc中,調用了_objc_rootDealloc函數(shù)
4泰涂、在_objc_rootDealloc中捷兰,調用了object_dispose函數(shù)
5、調用objc_destructInstance
6负敏、最后調用objc_clear_deallocating,詳細過程如下:
a. 從weak表中獲取廢棄對象的地址為鍵值的記錄
b. 將包含在記錄中的所有附有 weak修飾符變量的地址贡茅,賦值為 nil
c. 將weak表中該記錄刪除
d. 從引用計數(shù)表中刪除廢棄對象的地址為鍵值的記錄
10.iOS本地數(shù)據(jù)存儲安全
11.BAD_ACCESS的錯誤嗎?你是怎樣調試的其做?
BAD_ACCESS:不管什么時候當你遇到BAD_ACCESS這個錯誤顶考,那就意味著你向一個已經(jīng)釋放的對象發(fā)送消息。
BAD_ACCESS的本質:
在C和OC中妖泄,你一直在處理指針驹沿,指針無非是存儲另一個變量的內存地址的變量。當向一個對象發(fā)送消息時蹈胡,指向該對象的指針將會被引用渊季,這意味著,你獲取了指針所指的內存地址罚渐,并訪問該存儲區(qū)域的值却汉。
當該存儲器區(qū)域不再映射到你的應用時,或者換句話說荷并,該內存區(qū)域在你認為使用的時候沒有使用合砂,該內存區(qū)域是無法訪問的,這時內核會拋出一個異常(EXC)源织,表明你的應用程序不能訪問該存儲器區(qū)域(BAD_ACCESS).
當你碰到BAD_ACCESS翩伪,這意味著你試圖發(fā)送消息到的內存塊微猖,但內存塊無法執(zhí)行該消息。但是缘屹,在某些情況下凛剥,BAD_ACCESS是由被損壞的指針引起的,每當你的應用程序嘗試引用損壞的指針轻姿,一個異常就會被內核拋出犁珠。
Q:@synthesize和@dynamic分別有什么作用?
1.@property有兩個對應的詞踢代,一個是 @synthesize盲憎,一個是 @dynamic。如果 @synthesize和 @dynamic都沒寫胳挎,那么默認的就是@syntheszie var = _var;
2.@synthesize 的語義是如果你沒有手動實現(xiàn) setter 方法和 getter 方法饼疙,那么編譯器會自動為你加上這兩個方法。
3.@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現(xiàn)慕爬,不自動生成窑眯。(當然對于 readonly 的屬性只需提供 getter 即可)。假如一個屬性被聲明為 @dynamic var医窿,然后你沒有提供 @setter方法和 @getter 方法磅甩,編譯的時候沒問題,但是當程序運行到 instance.var = someVar姥卢,由于缺 setter 方法會導致程序崩潰卷要;或者當運行到 someVar = var 時,由于缺 getter 方法同樣會導致崩潰独榴。
///////////////////
@property有兩個關鍵詞, @synthesize(默認值)和@dynamic.
@synthesize表示系統(tǒng)會默認添加一個@syntheszie var = _var的實例變量, 并且自動生成setter和getter方法. @synthesize 合成實例變量有以下幾點規(guī)則:
如果指定了成員變量的名稱, 會生成一個指定的名稱的成員變量.
如果這個成員已經(jīng)存在就不再生成了.
如果沒有指定成員變量的名稱會自動生成一個屬性同名的成員變量.
@synthesize的使用場景:
同時重寫了setter和getter時
重寫了只讀屬性的getter時
在使用了@dynamic時
在@Protocol和category中定義屬性時
重載父類的屬性時, 來手動合成Ivar(實例變量/成員變量).
@dynamic表示我們不需要系統(tǒng)自動生成, 由用戶自己實現(xiàn), 如果沒有手動生成的話, 在使用過程中是會奔潰的.
Q:@synthesize合成實例變量的規(guī)則是什么僧叉?假如property名為foo,存在一個名為_foo的實例變量棺榔,那么還會自動合成新變量么瓶堕?
總結下 @synthesize 合成實例變量的規(guī)則,有以下幾點:
如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量,
如果這個成員已經(jīng)存在了就不再生成了.
如果是 @synthesize foo; 還會生成一個名稱為foo的成員變量症歇,也就是說:
如果沒有指定成員變量的名稱會自動生成一個屬性同名的成員變量,
如果是 @synthesize foo = _foo; 就不會生成成員變量了.
假如 property 名為 foo郎笆,存在一個名為 _foo 的實例變量,那么還會自動合成新變量么忘晤?
不會宛蚓。
Q:在有了自動合成屬性實例變量之后,@synthesize還有哪些使用場景德频?
什么情況下不會autosynthesis(自動合成)苍息?
同時重寫了 setter 和 getter 時
重寫了只讀屬性的 getter 時
使用了 @dynamic 時
在 @protocol 中定義的所有屬性
在 category 中定義的所有屬性
重載的屬性
當你在子類中重載了父類中的屬性,你必須 使用 @synthesize 來手動合成ivar壹置。
@synthesize 語法還有一個應用場景竞思,但是不太建議大家使用:
可以在類的實現(xiàn)代碼里通過 @synthesize 語法來指定實例變量的名字
@implementation CYLPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
可變數(shù)組&不可變數(shù)組修飾符的使用結論:
當修飾可變類型的屬性時,如NSMutableArray钞护、NSMutableDictionary盖喷、NSMutableString,用strong难咕。
當修飾不可變類型的屬性時课梳,如NSArray、NSDictionary余佃、NSString暮刃,用copy。
深拷貝與淺拷貝
淺拷貝就是拷貝之后爆土,并沒有真正的復制椭懊,而是復制對象和原對象都指向同一個地址
深拷貝是真正的復制了一份,復制的對象只想新的地址;
copy:對于可變對象為深拷貝步势,對于不可變對象為淺拷貝;
mutablecopy:始終為深拷貝;
淺拷貝簡單點說就是對內存地址的復制氧猬,讓目標對象指針和源對象指針指向同一片內存空間;
深拷貝: 內容拷貝,會創(chuàng)建一個新的對象坏瘩。深拷貝就是拷貝地址中的內容盅抚,讓目標對象產生新的內存區(qū)域,且將源內存區(qū)域中的內容復制到目標內存區(qū)域中;
Q:objc中的類方法和實例方法有什么本質區(qū)別和聯(lián)系倔矾?
(實例變量 = 成員變量 = ivar)
類方法:
1. 類方法是屬于類對象的
2. 類方法只能通過類對象調用
3. 類方法中的self是類對象
4. 類方法可以調用其他的類方法
5. 類方法中不能訪問成員變量
6. 類方法中不定直接調用對象方法
實例方法:
1. 實例方法是屬于實例對象的
2. 實例方法只能通過實例對象調用
3. 實例方法中的self是實例對象
4. 實例方法中可以訪問成員變量
5. 實例方法中直接調用實例方法
6. 實例方法中也可以調用類方法(通過類名)