iOS寶典--不斷更新中

category 和 extension 的區(qū)別

-分類(lèi)有名字,類(lèi)擴(kuò)展沒(méi)有分類(lèi)名字,是一種特殊的分類(lèi)

-分類(lèi)只能擴(kuò)展方法(屬性?xún)H僅是聲明,并沒(méi)真正實(shí)現(xiàn)),類(lèi)擴(kuò)展可以擴(kuò)展屬性、成員變量和方法

define 和 const常量有什么區(qū)別?

-define在預(yù)處理階段進(jìn)行替換,const常量在編譯階段使用

-宏不做類(lèi)型檢查,僅僅進(jìn)行替換,const常量有數(shù)據(jù)類(lèi)型,會(huì)執(zhí)行類(lèi)型檢查

-define不能調(diào)試,const常量可以調(diào)試

-define定義的常量在替換后運(yùn)行過(guò)程中會(huì)不斷地占用內(nèi)存,而const定義的常量存儲(chǔ)在數(shù)據(jù)段只有一份copy,效率更高

-define可以定義一些簡(jiǎn)單的函數(shù),const不可以

block和weak修飾符的區(qū)別?

__block不管是ARC還是MRC模式下都可以使用,可以修飾對(duì)象,也可以修飾基本數(shù)據(jù)類(lèi)型

__weak只能在ARC模式下使用,只能修飾對(duì)象(NSString),不能修飾基本數(shù)據(jù)類(lèi)型

block修飾的對(duì)象可以在block中被重新賦值,weak修飾的對(duì)象不可以

static關(guān)鍵字的作用

函數(shù)(方法)體內(nèi) static 變量的作用范圍為該函數(shù)體,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時(shí)仍維持上次的值;

在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外其它函數(shù)訪問(wèn);

在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明 它的模塊內(nèi);

在類(lèi)中的 static 成員變量屬于整個(gè)類(lèi)所擁有,對(duì)類(lèi)的所有對(duì)象只有一份拷貝;

在類(lèi)中的 static 成員函數(shù)屬于整個(gè)類(lèi)所擁有,這個(gè)函數(shù)不接收 this 指針,因而只能訪問(wèn)類(lèi)的static 成員變量

堆和棧的區(qū)別

-從管理方式來(lái)講

對(duì)于棧來(lái)講,是由編譯器自動(dòng)管理,無(wú)需我們手工控制;

對(duì)于堆來(lái)說(shuō),釋放工作由程序員控制,容易產(chǎn)生內(nèi)存泄露(memory leak)

-從申請(qǐng)大小大小方面講

??臻g比較小

堆控件比較大

-從數(shù)據(jù)存儲(chǔ)方面來(lái)講

棧空間中一般存儲(chǔ)基本類(lèi)型,對(duì)象的地址

堆空間一般存放對(duì)象本身,block的copy等

Objective-C使用什么機(jī)制管理對(duì)象內(nèi)存?

MRC 手動(dòng)引用計(jì)數(shù)

ARC 自動(dòng)引用計(jì)數(shù),現(xiàn)在通常ARC

通過(guò) retainCount 的機(jī)制來(lái)決定對(duì)象是否需要釋放。 每次 runloop 的時(shí)候,都會(huì)檢查對(duì)象的 retainCount,如果retainCount 為 0,說(shuō)明該對(duì)象沒(méi)有地方需要繼續(xù)使用了,可以釋放掉了

ARC通過(guò)什么方式幫助開(kāi)發(fā)者管理內(nèi)存?

通過(guò)編譯器在編譯的時(shí)候,插入類(lèi)似內(nèi)存管理的代碼

ARC是為了解決什么問(wèn)題誕生的?

-首先解釋ARC: automatic reference counting自動(dòng)引用計(jì)數(shù)

-了解MRC的缺點(diǎn)

在MRC時(shí)代當(dāng)我們要釋放一個(gè)堆內(nèi)存時(shí),首先要確定指向這個(gè)堆空間的指針都被release了

釋放指針指向的堆空間,首先要確定哪些指針指向同一個(gè)堆,這些指針只能釋放一次(MRC下即誰(shuí)創(chuàng)建,誰(shuí)釋放,避免重復(fù)釋放)

模塊化操作時(shí),對(duì)象可能被多個(gè)模塊創(chuàng)建和使用,不能確定最后由誰(shuí)去釋放

多線程操作時(shí),不確定哪個(gè)線程最后使用完畢

綜上所述,MRC有諸多缺點(diǎn),很容易造成內(nèi)存泄露和壞內(nèi)存的問(wèn)題,這時(shí)蘋(píng)果為盡量解決這個(gè)問(wèn)題,從而誕生了ARC

ARC下還會(huì)存在內(nèi)存泄露嗎?

-循環(huán)引用會(huì)導(dǎo)致內(nèi)存泄露

-Objective-C對(duì)象與CoreFoundation對(duì)象進(jìn)行橋接的時(shí)候如果管理不當(dāng)也會(huì)造成內(nèi)存泄露

-CoreFoundation中的對(duì)象不受ARC管理,需要開(kāi)發(fā)者手動(dòng)釋放

什么情況使用weak關(guān)鍵字,相比assign有什么不同?

-首先明白什么情況使用weak關(guān)鍵字?

在ARC中,在有可能出現(xiàn)循環(huán)引用的時(shí)候,往往要通過(guò)讓其中一端使用weak來(lái)解決,比如:delegate代理屬性,代理屬性也可使用assign

自身已經(jīng)對(duì)它進(jìn)行一次強(qiáng)引用,沒(méi)有必要再?gòu)?qiáng)引用一次,此時(shí)也會(huì)使用weak,自定義IBOutlet控件屬性一般也使用weak;當(dāng)然,也可以使用strong,但是建議使用weak

- weak 和 assign的不同點(diǎn)

weak策略在屬性所指的對(duì)象遭到摧毀時(shí),系統(tǒng)會(huì)將weak修飾的屬性對(duì)象的指針指向nil,在OC給nil發(fā)消息是不會(huì)有什么問(wèn)題的;如果使用assign策略在屬性所指的對(duì)象遭到摧毀時(shí),屬性對(duì)象指針還指向原來(lái)的對(duì)象,由于對(duì)象已經(jīng)被銷(xiāo)毀,這時(shí)候就產(chǎn)生了野指針,如果這時(shí)候在給此對(duì)象發(fā)送消息,很容造成程序奔潰

- assigin 可以用于修飾非OC對(duì)象,而weak必須用于OC對(duì)象

@property 的本質(zhì)是什么?

@property其實(shí)就是在編譯階段由編譯器自動(dòng)幫我們生成ivar成員變量,getter方法,setter方法

ivar、getter、setter是如何生成并添加到這個(gè)類(lèi)中的?

使用“自動(dòng)合成”( autosynthesis)

這個(gè)過(guò)程由編譯器在編譯階段執(zhí)行自動(dòng)合成,所以編輯器里看不到這些“合成方法”(synthesized method)的源代碼

除了生成getter、setter方法之外,編譯器還要自動(dòng)向類(lèi)中添加成員變量(在屬性名前面加下劃線,以此作為實(shí)例變量的名字)

為了搞清屬性是怎么實(shí)現(xiàn)的,反編譯相關(guān)的代碼,他大致生成了五個(gè)東西

// 該屬性的“偏移量” (offset),這個(gè)偏移量是“硬編碼” (hardcode),表示該變量距離存放對(duì)象的內(nèi)存區(qū)域的起始地址有多遠(yuǎn)OBJC_IVAR_$類(lèi)名$屬性名稱(chēng)// 方法對(duì)應(yīng)的實(shí)現(xiàn)函數(shù)setter與getter// 成員變量列表ivar_list// 方法列表method_list// 屬性列表prop_list

每次增加一個(gè)屬性,系統(tǒng)都會(huì)在ivar_list中添加一個(gè)成員變量的描述

在method_list中增加setter與getter方法的描述

在prop_list中增加一個(gè)屬性的描述

計(jì)算該屬性在對(duì)象中的偏移量

然后給出setter與getter方法對(duì)應(yīng)的實(shí)現(xiàn),在setter方法中從偏移量的位置開(kāi)始賦值,在getter方法中從偏移量開(kāi)始取值,為了能夠讀取正確字節(jié)數(shù),系統(tǒng)對(duì)象偏移量的指針類(lèi)型進(jìn)行了類(lèi)型強(qiáng)轉(zhuǎn)

@protocol 和 category 中如何使用 @property

在protocol中使用property只會(huì)生成setter和getter方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對(duì)象能實(shí)現(xiàn)該屬性

category 使用 @property也是只會(huì)生成setter和getter方法聲明,如果我們真的需要給category增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時(shí)的兩個(gè)函數(shù)

objc_setAssociatedObject

objc_getAssociatedObject

@property后面可以有哪些修飾符?

原子性---nonatomic特質(zhì)

如果不寫(xiě)默認(rèn)情況為atomic(系統(tǒng)會(huì)自動(dòng)加上同步鎖,影響性能)

在iOS開(kāi)發(fā)中盡量指定為nonatomic,這樣有助于提高程序的性能

讀/寫(xiě)權(quán)限---readwrite(讀寫(xiě))、readooly (只讀)

內(nèi)存管理語(yǔ)義---assign、strong、 weak、unsafe_unretained、copy

方法名---getter=、setter=

@property(nonatomic, getter=isOn)BOOLon;// setter=這種不常用,也**不推薦**使用。故不在這里給出寫(xiě)法

不常用的:nonnull,null_resettable,nullable

使用atomic一定是線程安全的嗎?

不是,atomic的本意是指屬性的存取方法是線程安全的,并不保證整個(gè)對(duì)象是線程安全的。

舉例:聲明一個(gè)NSMutableArray的原子屬性stuff,此時(shí)self.stuff 和self.stuff = othersulf都是線程安全的。但是,使用[self.stuff objectAtIndex:index]就不是線程安全的,需要用互斥鎖來(lái)保證線程安全性

@synthesize 和 @dynamic分別有什么作用

@property有兩個(gè)對(duì)應(yīng)的詞,一個(gè)是@synthesize,一個(gè)是@dynamic。如果@synthesize和@dynamic都沒(méi)寫(xiě),那么默認(rèn)的就是@syntheszie var = _var;

@synthesize的語(yǔ)義是如果你沒(méi)有手動(dòng)實(shí)現(xiàn)setter方法和getter方法,那么編譯器會(huì)自動(dòng)為你加上這兩個(gè)方法

@dynamic告訴編譯器:屬性的setter與getter方法由用戶(hù)自己實(shí)現(xiàn),不自動(dòng)生成(當(dāng)然對(duì)于readonly的屬性只需提供getter即可)

假如一個(gè)屬性被聲明為@dynamic var,然后你沒(méi)有提供@setter方法和@getter方法,編譯的時(shí)候沒(méi)問(wèn)題,但是當(dāng)程序運(yùn)行到instance.var = someVar,由于缺setter方法會(huì)導(dǎo)致程序崩潰;或者當(dāng)運(yùn)行到 someVar = instance.var時(shí),由于缺getter方法同樣會(huì)導(dǎo)致崩潰。編譯時(shí)沒(méi)問(wèn)題,運(yùn)行時(shí)才執(zhí)行相應(yīng)的方法,這就是所謂的動(dòng)態(tài)綁定

ARC下,不顯式指定任何屬性關(guān)鍵字時(shí),默認(rèn)的關(guān)鍵字都有哪些?

基本數(shù)據(jù):atomic,readwrite,assign

普通的OC對(duì)象:atomic,readwrite,strong

@synthesize合成實(shí)例變量的規(guī)則是什么?假如property名為foo,存在一個(gè)名為_(kāi)foo的實(shí)例變量,那么還會(huì)自動(dòng)合成新變量么?

先回答第二個(gè)問(wèn)題:不會(huì)

@synthesize合成成員變量的規(guī)則,有以下幾點(diǎn):

如果指定了成員變量的名稱(chēng),會(huì)生成一個(gè)指定的名稱(chēng)的成員變量

如果這個(gè)成員已經(jīng)存在了就不再生成了

如果指定@synthesize foo;就會(huì)生成一個(gè)名稱(chēng)為foo的成員變量,也就是說(shuō):會(huì)自動(dòng)生成一個(gè)屬性同名的成員變量

@interfaceXMGPerson:NSObject@property(nonatomic,assign)intage;@end@implementationXMGPerson// 不加這語(yǔ)句默認(rèn)生成的成員變量名為_(kāi)age// 如果加上這一句就會(huì)生成一個(gè)跟屬性名同名的成員變量@synthesizeage;@end

如果是 @synthesize foo = _foo; 就不會(huì)生成成員變量了

在有了自動(dòng)合成屬性實(shí)例變量之后,@synthesize還有哪些使用場(chǎng)景?

首先的搞清楚什么情況下不會(huì)autosynthesis(自動(dòng)合成)

同時(shí)重寫(xiě)了setter和getter時(shí)

重寫(xiě)了只讀屬性的getter時(shí)

使用了@dynamic時(shí)

在 @protocol 中定義的所有屬性

在 category 中定義的所有屬性

重載的屬性,當(dāng)你在子類(lèi)中重載了父類(lèi)中的屬性,必須使用@synthesize來(lái)手動(dòng)合成ivar

應(yīng)用場(chǎng)景

當(dāng)你同時(shí)重寫(xiě)了setter和getter時(shí),系統(tǒng)就不會(huì)生成ivar)。這時(shí)候有兩種選擇

手動(dòng)創(chuàng)建ivar

使用@synthesize foo = _foo;,關(guān)聯(lián)@property與ivar

可以用來(lái)修改成員變量名,一般不建議這么做,建議使用系統(tǒng)自動(dòng)生成的成員變量

怎么用 copy 關(guān)鍵字?

NSString、NSArray、NSDictionary等等經(jīng)常使用copy關(guān)鍵字,是因?yàn)樗麄冇袑?duì)應(yīng)的可變類(lèi)型:NSMutableString、NSMutableArray、NSMutableDictionary,為確保對(duì)象中的屬性值不會(huì)無(wú)意間變動(dòng),應(yīng)該在設(shè)置新屬性值時(shí)拷貝一份,保護(hù)其封裝性

block也經(jīng)常使用copy關(guān)鍵字

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

在ARC中寫(xiě)不寫(xiě)都行:對(duì)于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫(xiě)上copy,因?yàn)檫@樣顯示告知調(diào)用者“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了 copy 操作”

用@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用copy關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問(wèn)題?

因?yàn)楦割?lèi)指針可以指向子類(lèi)對(duì)象,使用copy的目的是為了讓本對(duì)象的屬性不受外界影響,使用copy無(wú)論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本.

如果我們使用是strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.

復(fù)制詳解

淺復(fù)制(shallow copy):在淺復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是指針復(fù)制。

深復(fù)制(one-level-deepcopy):在深復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象,至少有一層是深復(fù)制。

完全復(fù)制(real-deepcopy):在完全復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是對(duì)象復(fù)制。

非集合類(lèi)對(duì)象的copy與mutableCopy

[不可變對(duì)象copy]// 淺復(fù)制[不可變對(duì)象 mutableCopy]//深復(fù)制[可變對(duì)象copy]//深復(fù)制[可變對(duì)象 mutableCopy]//深復(fù)制

集合類(lèi)對(duì)象的copy與mutableCopy

[不可變對(duì)象copy]// 淺復(fù)制[不可變對(duì)象 mutableCopy]//單層深復(fù)制[可變對(duì)象copy]//單層深復(fù)制[可變對(duì)象 mutableCopy]//單層深復(fù)制

這里需要注意的是集合對(duì)象的內(nèi)容復(fù)制僅限于對(duì)象本身,對(duì)象元素仍然是指針復(fù)制

這個(gè)寫(xiě)法會(huì)出什么問(wèn)題: @property (copy) NSMutableArray *array;

因?yàn)閏opy策略拷貝出來(lái)的是一個(gè)不可變對(duì)象,然而卻把它當(dāng)成可變對(duì)象使用,很容易造成程序奔潰

這里還有一個(gè)問(wèn)題,該屬性使用了同步鎖,會(huì)在創(chuàng)建時(shí)生成一些額外的代碼用于幫助編寫(xiě)多線程程序,這會(huì)帶來(lái)性能問(wèn)題,通過(guò)聲明nonatomic可以節(jié)省這些雖然很小但是不必要額外開(kāi)銷(xiāo),在iOS開(kāi)發(fā)中應(yīng)該使用nonatomic替代atomic

如何讓自定義類(lèi)可以用 copy 修飾符?如何重寫(xiě)帶 copy 關(guān)鍵字的 setter?

若想令自己所寫(xiě)的對(duì)象具有拷貝功能,則需實(shí)現(xiàn)NSCopying協(xié)議。如果自定義的對(duì)象分為可變版本與不可變版本,那么就要同時(shí)實(shí)現(xiàn)NSCopyiog與NSMutableCopying協(xié)議,不過(guò)一般沒(méi)什么必要,實(shí)現(xiàn)NSCopying協(xié)議就夠了

// 實(shí)現(xiàn)不可變版本拷貝- (id)copyWithZone:(NSZone *)zone;// 實(shí)現(xiàn)可變版本拷貝- (id)mutableCopyWithZone:(NSZone *)zone;// 重寫(xiě)帶 copy 關(guān)鍵字的 setter- (void)setName:(NSString*)name{? ? _name = [namecopy];}

+(void)load; +(void)initialize;有什么用處?

+(void)load;

當(dāng)類(lèi)對(duì)象被引入項(xiàng)目時(shí), runtime 會(huì)向每一個(gè)類(lèi)對(duì)象發(fā)送 load 消息

load 方法會(huì)在每一個(gè)類(lèi)甚至分類(lèi)被引入時(shí)僅調(diào)用一次,調(diào)用的順序:父類(lèi)優(yōu)先于子類(lèi), 子類(lèi)優(yōu)先于分類(lèi)

由于 load 方法會(huì)在類(lèi)被import 時(shí)調(diào)用一次,而這時(shí)往往是改變類(lèi)的行為的最佳時(shí)機(jī),在這里可以使用例如method swizlling 來(lái)修改原有的方法

load 方法不會(huì)被類(lèi)自動(dòng)繼承

+(void)initialize;

也是在第一次使用這個(gè)類(lèi)的時(shí)候會(huì)調(diào)用這個(gè)方法,也就是說(shuō) initialize也是懶加載

總結(jié):

在Objective-C中,runtime會(huì)自動(dòng)調(diào)用每個(gè)類(lèi)的這兩個(gè)方法

+load會(huì)在類(lèi)初始加載時(shí)調(diào)用

+initialize會(huì)在第一次調(diào)用類(lèi)的類(lèi)方法或?qū)嵗椒ㄖ氨徽{(diào)用

這兩個(gè)方法是可選的,且只有在實(shí)現(xiàn)了它們時(shí)才會(huì)被調(diào)用

兩者的共同點(diǎn):兩個(gè)方法都只會(huì)被調(diào)用一次

Foundation對(duì)象與Core Foundation對(duì)象有什么區(qū)別

Foundation框架是使用OC實(shí)現(xiàn)的,Core Foundation是使用C實(shí)現(xiàn)的

Foundation對(duì)象 和 Core Foundation對(duì)象間的轉(zhuǎn)換:俗稱(chēng)橋接

ARC環(huán)境橋接關(guān)鍵字:

// 可用于Foundation對(duì)象 和 Core Foundation對(duì)象間的轉(zhuǎn)換__bridge// 用于Foundation對(duì)象 轉(zhuǎn)成 Core Foundation對(duì)象__bridge_retained// Core Foundation對(duì)象 轉(zhuǎn)成 Foundation對(duì)象__bridge_transfer

Foundation對(duì)象 轉(zhuǎn)成 Core Foundation對(duì)象

使用__bridge橋接

如果使用__bridge橋接,它僅僅是將strOC的地址給了strC, 并沒(méi)有轉(zhuǎn)移對(duì)象的所有權(quán),也就是說(shuō), 如果使用__bridge橋接, 那么如果strOC釋放了,strC也不能用了

注意:在ARC條件下,如果是使用__bridge橋接,那么strC可以不用主動(dòng)釋放, 因?yàn)锳RC會(huì)自動(dòng)管理strOC和strC

NSString*strOC1 = [NSStringstringWithFormat:@"abcdefg"];CFStringRef strC1 = (__bridge CFStringRef)strOC1;NSLog(@"%@ %@", strOC1, strC1);

使用__bridge_retained橋接

如果使用__bridge_retained橋接,它會(huì)將對(duì)象的所有權(quán)轉(zhuǎn)移給strC, 也就是說(shuō),即便strOC被釋放了, strC也可以使用

注意:在ARC條件下,如果是使用__bridge_retained橋接,那么strC必須自己手動(dòng)釋放,因?yàn)闃蚪拥臅r(shí)候已經(jīng)將對(duì)象的所有權(quán)轉(zhuǎn)移給了strC,而C語(yǔ)言的東西不是不歸ARC管理的

NSString*strOC2 = [NSStringstringWithFormat:@"abcdefg"];//? ? CFStringRef strC2 = (__bridge_retained CFStringRef)strOC2;CFStringRef strC2 = CFBridgingRetain(strOC2);// 這一句, 就等同于上一句CFRelease(strC2);

Core Foundation對(duì)象 轉(zhuǎn)成 Foundation對(duì)象

使用__bridge橋接

如果使用__bridge橋接,它僅僅是將strC的地址給了strOC, 并沒(méi)有轉(zhuǎn)移對(duì)象的所有權(quán)

也就是說(shuō)如果使用__bridge橋接,那么如果strC釋放了,strOC也不能用了

CFStringRef strC3 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);NSString*strOC3 = (__bridgeNSString*)strC3;CFRelease(strC3);

使用__bridge_transfer橋接

如果使用__bridge_transfer橋接,它會(huì)將對(duì)象的所有權(quán)轉(zhuǎn)移給strOC, 也就是說(shuō),即便strC被釋放了, strOC也可以使用

如果使用__bridge_transfer橋接, 他會(huì)自動(dòng)釋放strC, 也就是以后我們不用手動(dòng)釋放strC

CFStringRef strC4 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);//? ? NSString *strOC = (__bridge_transfer NSString *)strC;NSString*strOC4 = CFBridgingRelease(strC4);// 這一句, 就等同于上一句

MRC環(huán)境:直接強(qiáng)轉(zhuǎn)

-(void)bridgeInMRC{// 將Foundation對(duì)象轉(zhuǎn)換為Core Foundation對(duì)象,直接強(qiáng)制類(lèi)型轉(zhuǎn)換即可NSString*strOC1 = [NSStringstringWithFormat:@"xxxxxx"];? CFStringRef strC1 = (CFStringRef)strOC1;NSLog(@"%@ %@", strOC1, strC1);? [strOC1 release];? CFRelease(strC1);// 將Core Foundation對(duì)象轉(zhuǎn)換為Foundation對(duì)象,直接強(qiáng)制類(lèi)型轉(zhuǎn)換即可CFStringRef strC2 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);NSString*strOC2 = (NSString*)strC2;NSLog(@"%@ %@", strOC2, strC2);? [strOC2 release];? CFRelease(strC2);}

addObserver:forKeyPath:options:context:各個(gè)參數(shù)的作用分別是什么,observer中需要實(shí)現(xiàn)哪個(gè)方法才能獲得KVO回調(diào)?

/**

1. self.person:要監(jiān)聽(tīng)的對(duì)象

2. 參數(shù)說(shuō)明

1> 觀察者,負(fù)責(zé)處理監(jiān)聽(tīng)事件的對(duì)象

2> 要監(jiān)聽(tīng)的屬性

3> 觀察的選項(xiàng)(觀察新、舊值,也可以都觀察)

4> 上下文,用于傳遞數(shù)據(jù),可以利用上下文區(qū)分不同的監(jiān)聽(tīng)

*/[self.personaddObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];/**

*? 當(dāng)監(jiān)控的某個(gè)屬性的值改變了就會(huì)調(diào)用

*

*? @param keyPath 監(jiān)聽(tīng)的屬性名

*? @param object? 屬性所屬的對(duì)象

*? @param change? 屬性的修改情況(屬性原來(lái)的值、屬性最新的值)

*? @param context 傳遞的上下文數(shù)據(jù),與監(jiān)聽(tīng)的時(shí)候傳遞的一致,可以利用上下文區(qū)分不同的監(jiān)聽(tīng)

*/- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context{NSLog(@"%@對(duì)象的%@屬性改變了:%@", object, keyPath, change);}

KVO內(nèi)部實(shí)現(xiàn)原理

KVO是基于runtime機(jī)制實(shí)現(xiàn)的

當(dāng)某個(gè)類(lèi)的屬性對(duì)象第一次被觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類(lèi)的一個(gè)派生類(lèi),在這個(gè)派生類(lèi)中重寫(xiě)基類(lèi)中任何被觀察屬性的setter 方法。派生類(lèi)在被重寫(xiě)的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制

如果原類(lèi)為Person,那么生成的派生類(lèi)名為NSKVONotifying_Person

每個(gè)類(lèi)對(duì)象中都有一個(gè)isa指針指向當(dāng)前類(lèi),當(dāng)一個(gè)類(lèi)對(duì)象的第一次被觀察,那么系統(tǒng)會(huì)偷偷將isa指針指向動(dòng)態(tài)生成的派生類(lèi),從而在給被監(jiān)控屬性賦值時(shí)執(zhí)行的是派生類(lèi)的setter方法

鍵值觀察通知依賴(lài)于NSObject 的兩個(gè)方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個(gè)被觀察屬性發(fā)生改變之前, willChangeValueForKey: 一定會(huì)被調(diào)用,這就 會(huì)記錄舊的值。而當(dāng)改變發(fā)生后,didChangeValueForKey: 會(huì)被調(diào)用,繼而 observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用。

補(bǔ)充:KVO的這套實(shí)現(xiàn)機(jī)制中蘋(píng)果還偷偷重寫(xiě)了class方法,讓我們誤認(rèn)為還是使用的當(dāng)前類(lèi),從而達(dá)到隱藏生成的派生類(lèi)

如何手動(dòng)觸發(fā)一個(gè)value的KVO

自動(dòng)觸發(fā)的場(chǎng)景:在注冊(cè)KVO之前設(shè)置一個(gè)初始值,注冊(cè)之后,設(shè)置一個(gè)不一樣的值,就可以觸發(fā)了

想知道如何手動(dòng)觸發(fā),必須知道自動(dòng)觸發(fā) KVO 的原理,見(jiàn)上面的描述

手動(dòng)觸發(fā)演示

@property(nonatomic,strong)NSDate*now;- (void)viewDidLoad{? ? [superviewDidLoad];// “手動(dòng)觸發(fā)self.now的KVO”,必寫(xiě)。[selfwillChangeValueForKey:@"now"];// “手動(dòng)觸發(fā)self.now的KVO”,必寫(xiě)。[selfdidChangeValueForKey:@"now"];}

若一個(gè)類(lèi)有實(shí)例變量NSString *_foo,調(diào)用setValue:forKey:時(shí),是以foo還是_foo作為key?

都可以

KVC的keyPath中的集合運(yùn)算符如何使用?

必須用在集合對(duì)象上或普通對(duì)象的集合屬性上

簡(jiǎn)單集合運(yùn)算符有@avg, @count , @max , @min ,@sum

格式 @"@sum.age" 或 @"集合屬性.@max.age"???

KVC和KVO的keyPath一定是屬性么?

可以是成員變量

如何關(guān)閉默認(rèn)的KVO的默認(rèn)實(shí)現(xiàn),并進(jìn)入自定義的KVO實(shí)現(xiàn)?

如何自己動(dòng)手實(shí)現(xiàn) KVO

apple用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO?

此題就是問(wèn)KVO的實(shí)現(xiàn)原理

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • category 和 extension 的區(qū)別 分類(lèi)有名字,類(lèi)擴(kuò)展沒(méi)有分類(lèi)名字,是一種特殊的分類(lèi) 分類(lèi)只能擴(kuò)展方...
    Andyzhao閱讀 6,949評(píng)論 1 58
  • 一、category 和 extension 的區(qū)別?(分類(lèi)和擴(kuò)展的區(qū)別) 1,分類(lèi)有名字,類(lèi)擴(kuò)展沒(méi)有名字,是一種...
    閃電迷閱讀 803評(píng)論 0 3
  • category 和 extension 的區(qū)別? category :分類(lèi)有名字,類(lèi)擴(kuò)展沒(méi)i有分類(lèi)名字,是一種特...
    JonesCxy閱讀 328評(píng)論 0 1
  • category 和 extension 的區(qū)別? category :分類(lèi)有名字,類(lèi)擴(kuò)展沒(méi)i有分類(lèi)名字,是一種特...
    WSGNSLog閱讀 207評(píng)論 0 1
  • “今天晚上吃什么?!?“不吃,我減肥。” “吃不吃燒烤?!?“吃吃吃!” 坐辦公室的妹子都有一顆減肥的心,試圖減過(guò)...
    梅子卷閱讀 334評(píng)論 0 2

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