面試題

@property相關

@property的本質是什么?

@property = ivar + getter + setter;
“屬性” (property)有兩大概念:ivar(實例變量)终吼、存取方法(access method = getter + setter)。
編譯器會自動寫出一套存取方法油宜,用以訪問給定類型中具有給定名稱的變量。 所以你也可以這么說:
@property = getter + setter;

ivar怜姿、getter慎冤、setter 是如何生成并添加到這個類中的?

“自動合成”( autosynthesis)
編譯器會自動編寫訪問這些屬性所需的方法,此過程叫做“自動合成”(autosynthesis)沧卢。需要強調的是蚁堤,這個過程由編譯 器在編譯期執(zhí)行,所以編輯器里看不到這些“合成方法”(synthesized method)的源代碼但狭。除了生成方法代碼 getter披诗、setter 之外撬即,編譯器還要自動向類中添加適當類型的實例變量,并且在屬性名前面加下劃線呈队,以此作為實例變量的名字剥槐。在前例中,會生成兩個實例變量宪摧,其名稱分別為 _firstName與 _lastName粒竖。也可以在類的實現代碼里通過 @synthesize語法來指定實例變量的名字.

我為了搞清屬性是怎么實現的,曾經反編譯過相關的代碼,他大致生成了五個東西

OBJC_IVAR_類名屬性名稱 :該屬性的“偏移量” (offset),這個偏移量是“硬編碼” (hardcode)几于,表示該變量距離存放對象的內存區(qū)域的起始地址有多遠蕊苗。
setter 與 getter 方法對應的實現函數
ivar_list :成員變量列表
method_list :方法列表
prop_list :屬性列表
也就是說我們每次在增加一個屬性,系統都會在 ivar_list 中添加一個成員變量的描述,在 method_list 中增加 setter 與 getter 方法的描述,在屬性列表中增加一個屬性的描述,然后計算該屬性在對象中的偏移量,然后給出 setter 與 getter 方法對應的實現,在 setter 方法中從偏移量的位置開始賦值,在 getter 方法中從偏移量開始取值,為了能夠讀取正確字節(jié)數,系統對象偏移量的指針類型進行了類型強轉.

什么情況使用 weak 關鍵字,相比 assign 有什么不同沿彭?

1朽砰、在 ARC 中,在有可能出現循環(huán)引用的時候,往往要通過讓其中一端使用 weak 來解決,比如: delegate 代理屬性

2、自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak,自定義 IBOutlet 控件屬性一般也使用 weak喉刘;當然瞧柔,也可以使用strong。

不同點:

1饱搏、weak 此特質表明該屬性定義了一種“非擁有關系” (nonowning relationship)非剃。為這種屬性設置新值時置逻,設置方法既不保留新值推沸,也不釋放舊值。此特質同assign類似券坞, 然而在屬性所指的對象遭到摧毀時鬓催,屬性值也會清空(nil out)。 而 assign 的“設置方法”只會執(zhí)行針對“純量類型” (scalar type恨锚,例如 CGFloat 或 NSlnteger 等)的簡單賦值操作宇驾。
assign放在棧上,weak放在堆上

2猴伶、assign 可以用非 OC 對象,而 weak 必須用于 OC 對象

怎么用 copy 關鍵字课舍?

用途:

  1. NSString、NSArray他挎、NSDictionary 等等經常使用copy關鍵字筝尾,是因為他們有對應的可變類型:NSMutableString、NSMutableArray办桨、NSMutableDictionary筹淫;
  2. block 也經常使用 copy 關鍵字,具體原因見官方文檔:Objects Use Properties to Keep Track of Blocks

block 使用 copy 是從 MRC 遺留下來的“傳統”,在 MRC 中,方法內部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).

在 ARC 中寫不寫都行:

在 ARC 環(huán)境下呢撞,編譯器會根據情況自動將棧上的 block 復制到堆上损姜,比如以下情況:

  • block 作為函數返回值時

  • 將 block 賦值給 __strong 指針時(property 的 copy 屬性對應的是這一條)

  • block 作為 Cocoa API 中方法名含有 using Block 的方法參數時

  • block 作為 GCD API 的方法參數時
    其中饰剥, block 的 property 設置為 copy, 對應的是這一條:將 block 賦值給 __strong 指針時摧阅。

對于 block 使用 copy 還是 strong 效果是一樣的汰蓉,但寫上 copy 也無傷大雅,還能時刻提醒我們:編譯器自動對 block 進行了 copy 操作逸尖。如果不寫 copy 古沥,該類的調用者有可能會忘記或者根本不知道“編譯器會自動對 block 進行了 copy 操作”,他們有可能會在調用之前自行拷貝屬性值娇跟。這種操作多余而低效岩齿。你也許會感覺我這種做法有些怪異,不需要寫還依然寫苞俘。如果你這樣想盹沈,其實是你“日用而不知”,你平時開發(fā)中是經常在用我說的這種做法的吃谣,比如下面的屬性不寫copy也行乞封,但是你會選擇寫還是不寫呢?

下面做下解釋: copy 此特質所表達的所屬關系與 strong 類似岗憋。然而設置方法并不保留新值肃晚,而是將其“拷貝” (copy)。 當屬性類型為 NSString 時仔戈,經常用此特質來保護其封裝性关串,因為傳遞給設置方法的新值有可能指向一個 NSMutableString 類的實例。這個類是 NSString 的子類监徘,表示一種可修改其值的字符串晋修,此時若是不拷貝字符串,那么設置完屬性之后凰盔,字符串的值就可能會在對象不知情的情況下遭人更改墓卦。所以,這時就要拷貝一份“不可變” (immutable)的字符串户敬,確保對象中的字符串值不會無意間變動落剪。只要實現屬性所用的對象是“可變的” (mutable),就應該在設置新屬性值時拷貝一份尿庐。

這個寫法會出什么問題: @property (copy) NSMutableArray *array;

兩個問題:
1忠怖、添加,刪除,修改數組內的元素的時候,程序會因為找不到對應的方法而崩潰.因為 copy 就是復制一個不可變 NSArray 的對象;
2屁倔、使用了 atomic 屬性會嚴重影響性能 脑又;(該屬性使用了互斥鎖(atomic 的底層實現,老版本是自旋鎖,iOS10開始是互斥鎖--spinlock底層實現改變了问麸。)往衷,會在創(chuàng)建時生成一些額外的代碼用于幫助編寫多線程程序,這會帶來性能問題严卖,通過聲明 nonatomic 可以節(jié)省這些雖然很小但是不必要額外開銷席舍。)

如何讓自己的類用 copy 修飾符?如何重寫帶 copy 關鍵字的 setter哮笆?

若想令自己所寫的對象具有拷貝功能来颤,則需實現 NSCopying 協議。如果自定義的對象分為可變版本與不可變版本稠肘,那么就要同時實現 NSCopying 與 NSMutableCopying 協議福铅。
具體步驟:

需聲明該類遵從 NSCopying 協議
實現 NSCopying 協議。該協議只有一個方法:

  • (id)copyWithZone:(NSZone *)zone;
@protocol 和 category 中如何使用 @property

1项阴、在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協議的對象能實現該屬性

2滑黔、category 使用 @property 也是只會生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實現,需要借助于運行時的兩個函數:

3、objc_setAssociatedObject

4环揽、objc_getAssociatedObject

runtime 如何實現 weak 屬性

weak 此特質表明該屬性定義了一種“非擁有關系” (nonowning relationship)略荡。為這種屬性設置新值時,設置方法既不保留新值歉胶,也不釋放舊值汛兜。此特質同 assign 類似, 然而在屬性所指的對象遭到摧毀時通今,屬性值也會清空(nil out)粥谬。

那么 runtime 如何實現 weak 變量的自動置nil?

runtime 對注冊的類衡创, 會進行布局帝嗡,對于 weak 對象會放入一個 hash 表中晶通。 用 weak 指向的對象內存地址作為 key璃氢,當此對象的引用計數為0的時候會 dealloc,假如 weak 指向的對象內存地址是a狮辽,那么就會以a為鍵一也, 在這個 weak 表中搜索,找到所有以a為鍵的 weak 對象喉脖,從而設置為 nil椰苟。
而如果a是由 assign 修飾的,則: 在 b 非 nil 時树叽,a 和 b 指向同一個內存地址舆蝴,在 b 變 nil 時,a 還是指向該內存地址,變野指針洁仗。此時向 a 發(fā)送消息會產生崩潰层皱。
weak 修飾的指針默認值是 nil (在Objective-C中向nil發(fā)送消息是安全的)

@property中有哪些屬性關鍵字?/ @property 后面可以有哪些修飾符赠潦?

屬性可以擁有的特質分為四類:
1叫胖、原子性--- nonatomic 特質

在默認情況下,由編譯器合成的方法會通過鎖定機制確保其原子性(atomicity)她奥。如果屬性具備 nonatomic 特質瓮增,則不使用互斥鎖(atomic 的底層實現,老版本是自旋鎖哩俭,iOS10開始是互斥鎖--spinlock底層實現改變了绷跑。)。請注意凡资,盡管沒有名為“atomic”的特質(如果某屬性不具備 nonatomic 特質你踩,那它就是“原子的” ( atomic) ),但是仍然可以在屬性特質中寫明這一點讳苦,編譯器不會報錯带膜。若是自己定義存取方法,那么就應該遵從與屬性特質相符的原子性鸳谜。

2膝藕、讀/寫權限---readwrite(讀寫)、readonly (只讀)

3咐扭、內存管理語義---assign芭挽、strong、 weak蝗肪、unsafe_unretained袜爪、copy

4、方法名---getter=<name> 薛闪、setter=<name>

weak屬性需要在dealloc中置nil么辛馆?

在ARC環(huán)境無論是強指針還是弱指針都無需在 dealloc 設置為 nil , ARC 會自動幫我們處理

@synthesize和@dynamic分別有什么作用豁延?

1昙篙、@property有兩個對應的詞,一個是 @synthesize诱咏,一個是 @dynamic苔可。如果 @synthesize和 @dynamic都沒寫,那么默認的就是@syntheszie var = _var;

2袋狞、@synthesize 的語義是如果你沒有手動實現 setter 方法和 getter 方法焚辅,那么編譯器會自動為你加上這兩個方法映屋。

3、@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現同蜻,不自動生成秧荆。(當然對于 readonly 的屬性只需提供 getter 即可)。假如一個屬性被聲明為 @dynamic var埃仪,然后你沒有提供 @setter方法和 @getter 方法乙濒,編譯的時候沒問題,但是當程序運行到 instance.var = someVar卵蛉,由于缺 setter 方法會導致程序崩潰颁股;或者當運行到 someVar = var 時,由于缺 getter 方法同樣會導致崩潰傻丝。編譯時沒問題甘有,運行時才執(zhí)行相應的方法,這就是所謂的動態(tài)綁定葡缰。

ARC下亏掀,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些泛释?

1 對應基本數據類型默認關鍵字是
atomic
readwrite
assign

2 對于普通的 Objective-C 對象
atomic
readwrite
strong

用@property聲明的NSString(或NSArray滤愕,NSDictionary)經常使用copy關鍵字,為什么怜校?如果改用strong關鍵字间影,可能造成什么問題?

iOS 集合的深復制與淺復制

1茄茁、因為父類指針可以指向子類對象,使用 copy 的目的是為了讓本對象的屬性不受外界影響,使用 copy 無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.

2魂贬、如果我們使用是 strong ,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.

copy 此特質所表達的所屬關系與 strong 類似。然而設置方法并不保留新值裙顽,而是將其“拷貝” (copy)付燥。 當屬性類型為 NSString 時,經常用此特質來保護其封裝性愈犹,因為傳遞給設置方法的新值有可能指向一個 NSMutableString 類的實例键科。這個類是 NSString 的子類,表示一種可修改其值的字符串甘萧,此時若是不拷貝字符串萝嘁,那么設置完屬性之后梆掸,字符串的值就可能會在對象不知情的情況下遭人更改扬卷。所以,這時就要拷貝一份“不可變” (immutable)的字符串酸钦,確保對象中的字符串值不會無意間變動怪得。只要實現屬性所用的對象是“可變的” (mutable),就應該在設置新屬性值時拷貝一份。

  1. 對非集合類對象的copy操作:(系統非集合類對象指的是 NSString, NSNumber ... 之類的對象)
    在非集合類對象中:對 immutable 對象進行 copy 操作徒恋,是指針復制蚕断,mutableCopy 操作時內容復制;對 mutable 對象進行 copy 和 mutableCopy 都是內容復制入挣。用代碼簡單表示如下:

[immutableObject copy] // 淺復制
[immutableObject mutableCopy] //深復制
[mutableObject copy] //深復制
[mutableObject mutableCopy] //深復制

2亿乳、集合類對象的copy與mutableCopy
集合類對象是指 NSArray、NSDictionary径筏、NSSet ... 之類的對象葛假。下面先看集合類immutable對象使用 copy 和 mutableCopy 的一個例子:
[immutableObject copy] // 淺復制
[immutableObject mutableCopy] //單層深復制
[mutableObject copy] //單層深復制
[mutableObject mutableCopy] //單層深復制

  • 淺復制(shallow copy):在淺復制操作時,對于被復制對象的每一層都是指針復制滋恬。
  • 深復制(one-level-deep copy):在深復制操作時聊训,對于被復制對象,至少有一層是深復制恢氯。
  • 完全復制(real-deep copy):在完全復制操作時带斑,對于被復制對象的每一層都是對象復制。

系統對象的copy與mutableCopy方法
不管是集合類對象勋拟,還是非集合類對象勋磕,接收到copy和mutableCopy消息時,都遵循以下準則:

  • copy返回imutable對象敢靡;所以朋凉,如果對copy返回值使用mutable對象接口就會crash;
  • mutableCopy返回mutable對象醋安;
集合對象的完全復制

方法一:使用 initWith***: copyItems:YES 方法
自定義集合對象使用這個方法杂彭,對象必須遵守NSCopying協議,并重寫- (id)copyWithZone:(NSZone *)zone方法吓揪。(系統類方法已經實現)亲怠。

方法二:先將集合進行歸檔,然后再解檔柠辞。
通常我們對模型數組完全復制团秽,先將模型數組轉換為data數組,再將data數組轉換為模型數組叭首,即可习勤。

最后說個題外的東西,在搜集資料的過程中焙格,發(fā)現一個有可能犯錯的點
NSString *str = @"string";
str = @"newString";
上面這段代碼图毕,在執(zhí)行第二行代碼后,內存地址發(fā)生了變化眷唉。乍一看予颤,有點意外囤官。按照 C 語言的經驗,初始化一個字符串之后蛤虐,字符串的首地址就被確定下來党饮,不管之后如何修改字符串內容,這個地址都不會改變驳庭。但此處第二行并不是對 str 指向的內存地址重新賦值刑顺,因為賦值操作符左邊的 str 是一個指針,也就是說此處修改的是內存地址饲常。

所以第二行應該這樣理解:將@"newStirng"當做一個新的對象捏检,將這段對象的內存地址賦值給str。

@synthesize合成實例變量的規(guī)則是什么不皆?假如property名為foo贯城,存在一個名為_foo的實例變量,那么還會自動合成新變量么霹娄?

實例變量 = 成員變量 = ivar

如果使用了屬性的話能犯,那么編譯器就會自動編寫訪問屬性所需的方法,此過程叫做“自動合成”( auto synthesis)犬耻。需要強調的是踩晶,這個過程由編譯器在編譯期執(zhí)行,所以編輯器里看不到這些“合成方法” (synthesized method)的源代碼枕磁。除了生成方法代碼之外渡蜻,編譯器還要自動向類中添加適當類型的實例變量,并且在屬性名前面加下劃線计济,以此作為實例變量的名字茸苇。

@interface CYLPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end

在上例中,會生成兩個實例變量沦寂,其名稱分別為 _firstName 與 _lastName学密。也可以在類的實現代碼里通過 @synthesize 語法來指定實例變量的名字:

@implementation CYLPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end

上述語法會將生成的實例變量命名為 _myFirstName 與 _myLastName ,而不再使用默認的名字传藏。一般情況下無須修改默認的實例變量名腻暮,但是如果你不喜歡以“下劃線”來命名實例變量,那么可以用這個辦法將其改為自己想要的名字毯侦。筆者還是推薦使用默認的命名方案哭靖,因為如果所有人都堅持這套方案,那么寫出來的代碼大家都能看得懂侈离。

總結下 @synthesize 合成實例變量的規(guī)則试幽,有以下幾點:

1 如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量,

2 如果這個成員已經存在了就不再生成了

3 如果是 @synthesize foo; 還會生成一個名稱為foo的成員變量,也就是說:

如果沒有指定成員變量的名稱會自動生成一個屬性同名的成員變量,

4 如果是 @synthesize foo = _foo; 就不會生成成員變量了.

假如 property 名為 foo霍狰,存在一個名為 _foo 的實例變量抡草,那么還會自動合成新變量么饰及?
不會蔗坯。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末康震,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子宾濒,更是在濱河造成了極大的恐慌腿短,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绘梦,死亡現場離奇詭異橘忱,居然都是意外死亡,警方通過查閱死者的電腦和手機卸奉,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門钝诚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人榄棵,你說我怎么就攤上這事凝颇。” “怎么了疹鳄?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵拧略,是天一觀的道長。 經常有香客問我瘪弓,道長垫蛆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任腺怯,我火速辦了婚禮袱饭,結果婚禮上,老公的妹妹穿的比我還像新娘呛占。我一直安慰自己宁赤,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布栓票。 她就那樣靜靜地躺著决左,像睡著了一般。 火紅的嫁衣襯著肌膚如雪走贪。 梳的紋絲不亂的頭發(fā)上佛猛,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音坠狡,去河邊找鬼继找。 笑死,一個胖子當著我的面吹牛逃沿,可吹牛的內容都是我干的婴渡。 我是一名探鬼主播幻锁,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼边臼!你這毒婦竟也來了哄尔?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤柠并,失蹤者是張志新(化名)和其女友劉穎岭接,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體臼予,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡鸣戴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了粘拾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窄锅。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缰雇,靈堂內的尸體忽然破棺而出入偷,到底是詐尸還是另有隱情,我是刑警寧澤寓涨,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布盯串,位于F島的核電站,受9級特大地震影響戒良,放射性物質發(fā)生泄漏体捏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一糯崎、第九天 我趴在偏房一處隱蔽的房頂上張望几缭。 院中可真熱鬧,春花似錦沃呢、人聲如沸年栓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽某抓。三九已至械拍,卻和暖如春忌栅,著一層夾襖步出監(jiān)牢的瞬間蟋座,已是汗流浹背值依。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碌补,地道東北人趁仙。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓感论,卻偏偏與公主長得像,于是被迫代替她去往敵國和親曲尸。 傳聞我的和親對象是個殘疾皇子赋续,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354