真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

ios開發(fā)kvc,ios開發(fā)kvc原理

淺談ios之kvc底層執(zhí)行原理

開發(fā)中常用賦值方式:1、直接通過setter方法賦值;2、通過kvc賦值

公司主營業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)推出陽曲免費做網(wǎng)站回饋大家。

KVC:鍵值編碼,使用字符串訪問對象的屬性

使用方式:

例如對key為name賦值、取值

當(dāng)通過setValue:forKey:賦值時,其底層流程為:

1、查找是否有setName,_setName,setIsName的set方法,如果有任意一種,直接賦值。若沒有進(jìn)入第二步

2、查找accessInstanceVariablesDirectly是否允許訪問成員變量,若為YES,則查找實例變量_name,_isName,name,isName,查到任意一個則進(jìn)行賦值

3、setter方法和實例變量都沒有找到,系統(tǒng)會執(zhí)行該對象的setValue:forUndefinekey:拋異常

當(dāng)通過valueForKey取值時,其底層執(zhí)行流程為:

1、查找是否有g(shù)etName,name,isName,_name的get方法,若找到則根據(jù)找到的屬性值類型,返回對應(yīng)結(jié)果。若沒找到進(jìn)入第二步

2、檢查InstanceVariablesDirectly是否為YES,查找_name,_isName,name,isName,查到直接獲取對應(yīng)的值

3、getter方法和實例變量都沒找到,系統(tǒng)會執(zhí)行valueForUndefinekey方法拋異常

什么是KVC

在iOS開發(fā)過程中,我們經(jīng)常會聽到或者用到KVO/KVC,但是對于什么是KVO和KVC,我們可能沒有那么了解。下面先讓我們來了解一下什么是KVC.

什么是KVC

在蘋果的官方文檔中是這樣描述KVC的:它是一種通過字符串描述符而不是通過調(diào)用訪問方法或者直接使用實例變量的非直接的訪問對象屬性的機(jī)制,說白了就是KVO是一種通過非常規(guī)方法訪問成員變量或者屬性的機(jī)制,這種非常規(guī)方式就是通過一個字符串標(biāo)示符也就是所謂的key來訪問屬性或者成員變量。而這個key一般就是屬性名或者實例變量名。

對于KVC的基本的方法都定義在NSKeyValueCoding的非正式協(xié)議中,并且NSObject默認(rèn)實現(xiàn)了該協(xié)議。

KVC不僅支持對象類型,也支持?jǐn)?shù)值類型和結(jié)構(gòu)體。非對象類型的參數(shù)和返回類型會自動封裝成NSValue或NSNumber類型。

KVO可以用來訪問三種不同的對象值類型:屬性、一對一關(guān)系、一對多關(guān)系

屬性可以是諸如數(shù)值、字符串、bool類型等簡單的值。也可以NSNumber或者NSColor這樣的對象值。

在一對一關(guān)系里的對象可以擁有它自己的屬性,這些屬性可以在不改變對象的情況下被改變。像UIView的superView的屬性,我們可以更改superView的屬性,而不需要更改UIView。

一對多屬性是一些相關(guān)對象的集合。通常用NSArray或者NSSet來存儲這些集合。KVO也允許用戶自定義集合類,但依然是像訪問NSArray或者NSSet一樣訪問它們。

鍵和鍵路徑

鍵是用來標(biāo)識一個對象屬性的字符串。一般情況下,鍵就是訪問方法或者是對象的實例變量的名字。鍵必須是ASCII編碼,以小寫字母開頭,并且不能包含空格。舉幾個鍵的例子:age、firstName、lastNmame等。

鍵路徑是一串由點分隔的鍵組成的字符串,它是用來遍歷一系列的對象屬性的。第一個鍵的屬性是跟接收者相關(guān)的,而每一個子系列是跟前一個屬性相關(guān)的。比如鍵路徑address.street,這個鍵路徑會首先從接收者獲得address屬性,然后從address屬性中獲得street屬性。

用KVC獲得屬性的值

方法valueForKey:會返回跟接收者相關(guān)的key的值。如果對于指定的key沒有訪問器或者實例變量,則給自己發(fā)送一個valueForUndefinedKey:消息,這個方法的默認(rèn)實現(xiàn)是拋出一個NSUndefinedKeyException。子類可以重寫這個方法。

同樣的,valueForKeyPath:返回跟接收者相關(guān)的鍵路徑的值。對于子系列中任何不遵循KVC的對象,都會收到一個valueForUndefineKey:消息。

dictionaryWithValuesForKeys:會檢索數(shù)組中所有跟接收者相關(guān)的key的值。返回的NSDictionary中包含了數(shù)組中所有key的值。

注意:集合對象,比如NSArray、NSSet和NSDictionary中不能將nil作為一個值。相反的,應(yīng)該用NSNull對象代替nil。NSNull是一個代表nil的對象屬性。dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:方法的實現(xiàn)中,默認(rèn)會在nil和NSNull之間進(jìn)行轉(zhuǎn)換。在你的對象中,不需要對nil做顯示的測試。

用KVC設(shè)置屬性的值

方法setValue:forKey:是將接收者中相關(guān)key的值設(shè)置成指定的值。在這個方法的實現(xiàn)中,會將NSValue的值轉(zhuǎn)換成普通的數(shù)值然后賦給屬性。

如果指定的key不存在,會給接收者發(fā)送一個setValue:forUndefinedKey:消息。這個方法的默認(rèn)實現(xiàn)是拋出一個NSUndefinedKeyException異常,子類可以重寫這個方法來自定義默認(rèn)行為。

方法setValue:forKeyPath:的實現(xiàn)跟前面的一樣,只不過它是用來處理鍵路徑的。

setValuesForKeysWithDictionary:方法是用指定字典里的值來賦給接收者相關(guān)的屬性。這個方法的默認(rèn)實現(xiàn)是對每一對鍵-值都調(diào)用一次setValue:forKey:方法,并且自動將nil轉(zhuǎn)成NSNull。

最后,你要關(guān)心的當(dāng)嘗試將一個nil值賦給一個非對象類型的時候該怎么辦。這種情況下,接收者會發(fā)出一個setNilValueForKey:消息,這個方法的默認(rèn)實現(xiàn)是拋出一個NSInvalidArgumentException。在你的應(yīng)用中可以重寫這個方法來定義一個默認(rèn)值,然后用新的值觸發(fā)setValue:forKey

iOS中的KVC簡介

Key-Value Coding 俗稱"鍵值編碼",蘋果官方簡稱這個模式為KVC編碼模式,也就是說可以通過一個Key去訪問某一個屬性,或者給對象去賦值,而不需要去明確存取方法,這樣就可以動態(tài)的訪問和修改對象的屬性,而不是在編譯的時候去確定,這也是iOS開發(fā)中的一大便利,其實有很多的框架和功能是用KVC去實現(xiàn)的,這個技術(shù)存在已經(jīng)很長時間了,在網(wǎng)上也有很多相關(guān)的教程去教童鞋們?nèi)绾稳ナ褂肒VC,在這里,我們就只是簡單的介紹一下KVC的底層實現(xiàn)和使用方法。

從蘋果官方對KVC的解釋來看,其實KVC在Fundation框架中占有很高的地位,諸如Core-Data之類的框架都使用到了KVC技術(shù),我們在開發(fā)中可能常見的API有:

NSKeyValueCoding類別中還有其他的一些比較重要方法,如下:

說起KVC的執(zhí)行流程,我們有很多初級工程師都不大清楚,只知道KVC是如何使用的,而不知道KVC是怎么Key的尋找策略的。下圖我們借鑒了MJ老師的兩幅PPT來解釋

上圖我們可以看到

簡單說KVC機(jī)制在設(shè)值的時候會按照 setKey: 》_setKey 》_key 》_isKey 》key 》 isKey 順序搜索成員并進(jìn)行賦值操作,但是如果開發(fā)者重寫了類方法+ (BOOL)accessInstanceVarialbesDirectly并且讓其返回NO,這樣在搜索的時候會直接從步驟 1跳轉(zhuǎn)到步驟5 。

舉一個例子,我們先創(chuàng)建一個Person類

然后用KVC賦值

最終在控制臺打印的結(jié)果是

當(dāng)調(diào)用valueForKey:方法時,KVC對key的搜索順序有點不同于setValue:forKey:方法,大致步驟如下:

最終打印為

上述可以看出,當(dāng)Key查找不到值的時候會走 valueForUndefinedKey 方法中拋出異常

類的成員變量有可能是自定義類或其他復(fù)雜數(shù)據(jù)類型,對這種成員變量可以先用KVC獲取該屬性,然后再用KVC來獲取這個自定義類的屬性,這樣一層層去獲取,但這樣比較繁瑣。對此KVC提供一個解決方案,就是鍵路徑keyPath,顧名思義就是按照路徑尋找key。主要有兩個以下兩個方法:

在上述Person中我們創(chuàng)建一個Cat類

在Cat類中我們創(chuàng)建一個屬性 name

我們?nèi)绻枰肒VC對Person對象中Cat對象賦值的話,我們就必須用到KeyPath了

KVC對于keyPath的搜索機(jī)制第一步就是分離key,用小數(shù)點.來分割key,然后再像普通key一樣按照上面介紹的順序搜索。

使用KVC過程中最常見的異常就是不小心使用了錯誤的key,或者在設(shè)值中不小心傳了nil的值,KVC有專門的方法處理這些異常。

該方法返回一個可變有序數(shù)組。對于無序的容器,可以用以下方法:

該方法返回一個可變的無序集合。同時他們也有對應(yīng)的keyPath版本:

當(dāng)NSDictionary對象使用KVC時,valueForKey:的表現(xiàn)行為和objectForKey:一樣,使用valueForKeyPath:可訪問多層嵌套的字典會方便點,在KVC中有兩個關(guān)于NSDictionary的方法:

當(dāng)開發(fā)者需要驗證能不能用KVC設(shè)定某個值時,就需要在進(jìn)行KVC賦值前驗證值value的有效性,API文檔里面提供下面的方法進(jìn)行判斷值的有效性。

該方法的工作原理:先找一下你的類中是否實現(xiàn)了方法-(BOOL)validateKey:error:,如果實現(xiàn)了就會根據(jù)實現(xiàn)方法里面的自定義邏輯返回NO或者YES,如果沒有實現(xiàn)這個方法,則系統(tǒng)默認(rèn)返回就是YES。

輸出結(jié)果為

這里首先調(diào)用方法 [self validateValue:value forKey:key error:error] ;,這里,由于我實現(xiàn)了方法- (BOOL)validatePersonName:(id *)value error:(out NSError * _Nullable __autoreleasing *)outError ,所以就在這里進(jìn)行值value有效性的判斷,這里 [name isEqualToString:@"小明"] 我就給返回YES,否則就返回NO。

KVC在iOS開發(fā)中非常的靈活,提供了開發(fā)者更多的賦值和取值操作的選擇,它的有點明顯,缺點也有,如果key只寫錯,編寫的時候不會報錯,但是運(yùn)行的時候會報錯,在實際開發(fā)中需要開發(fā)者時刻小心自己輸入的鍵值,也時刻提醒著開發(fā)者一旦使用KVC就要做容錯處理。

iOS KVC的理解與crash場景

實現(xiàn)原理:

KVC的賦值本質(zhì)上只是調(diào)用了屬性的setter方法,setter方法會按照setKey、_setKey、setIsKey的優(yōu)先級進(jìn)行調(diào)用,還沒有,則按_key、_isKey、key、isKey查找成員變量。

如果accessInstanceVariablesDirectly返回NO,則不會查找_key、_isKey、key、isKey,會直接調(diào)用- (void)setValue:(id)value forUndefinedKey:(NSString *)key。

若查找到isKey還是沒找到,也會調(diào)用(void)setValue:(id)value forUndefinedKey:(NSString *)key,該方法默認(rèn)會拋出異常。

crash的場景:

key 不是對象的屬性,造成崩潰。

keyPath 不正確,造成崩潰。

key 為 nil,造成崩潰。

value 為 nil,為非對象設(shè)值,造成崩潰: [objc setValue:nil forKey:@"age"];

crash的防護(hù):

load方法中對setValue: forUndefinedKey:和valueForUndefinedKey方法做方法替換,判斷key或value為nil時return;

iOS開發(fā)常見問題

如果 xcode 中配置文件安裝比較多,有些用不到了,可以到下面路徑進(jìn)行刪除.

~/Library/MobileDevice/Provisioning Profiles

1 直接剪切

通過打印 tabBar 的子 view, 我們發(fā)現(xiàn)黑線的 y 值是-0.5;

這種方法雖然直接,對于去除 navi 的黑線也是有效的.但是本人不推薦這么去做.如果你的應(yīng)用里沒有突出的當(dāng)然是可以的.

2 刪除黑線

和刪除 navi 的差不多,不過不用進(jìn)行二次遍歷.

當(dāng)然這種刪除方式,適合自定義的 tabBar, 如果是使用tabbarController 的屬性的話,就不適用了.因為在tabbarController里我們拿不到 tabBar 的 subViews. 通過打印,會發(fā)現(xiàn)是空數(shù)組.這時我們可以使用KVC 使用自定義的 tabBar 去替換系統(tǒng)屬性.

后臺返回的經(jīng)常會見到(null), 那么null是什么鬼, 改怎么處理.使用.通過測試,我們可以看出來下面的結(jié)果.

由上面得出以下結(jié)論.

1.nil, 表示的是空指針,指向的對象是空,地址是0x0, 打印返回的結(jié)果是(null).

2.[NSNull null],表示一個對象是空值,是有內(nèi)存地址的.打印結(jié)果是null.

3.對于字符串來講一個空字符串和字符串是空是兩種概念.如 str 和str2,兩種寫法. 如果有時候不確定返回的字符串是@""還是 nil, 最好使用 [str isEqualToString:@""] || str.length == 0 這種判斷方式. str 只使用** [str isEqualToString:@""] ** 是無效的.

在某個功能中,后臺返回的是字符串,但是要顯示在不同的label 中,才注意到了這個方法.

由于現(xiàn)在的請求是 HTTP,運(yùn)行時報以下信息內(nèi)容

App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

這時候需要在info.plist中添加一個字段.

通過打印webView 的 subViews 發(fā)現(xiàn), webView 的子 View 中有個 _UIWebViewScrollView 的成員變量, 所以進(jìn)行猜測.

注意到了 webView 有一個scrollView 的屬性,那么更簡單的做法是:

只需要給 tableView 的 tableFooterView 添加一個空的 View 即可

有一個屬性 background ,在習(xí)慣性找backgroundImage 的時候,有時忽略了這個屬性.

有時候需要替換字符串里的字符.

在實際應(yīng)用中需要獲取設(shè)備的信息.系統(tǒng)給了一個類UIDevice, 可以用來獲取一些基本信息.

如果要獲取具體的設(shè)備型號,比如要給專門的機(jī)型推送一些服務(wù)的話.那個就得拿到設(shè)備的類型.

通過拿到產(chǎn)品類型我們可以進(jìn)而判斷出機(jī)型. 下面是網(wǎng)上總結(jié)出來的

由于創(chuàng)建項目時,項目名稱包含中文會,Bundle Identifier 中會直接使用-代替中文.所以項目名稱一般會使用英文,實在不行要使用拼音.這樣的話,安裝到手機(jī)中的名稱要顯示自己想要的名稱的話.

需要在** info.plist ** 中添加一項.** Bundle display name **.

對應(yīng)的 Value 就是安裝app 后,顯示的名稱.

由于現(xiàn)在是Retina 屏幕,使用 CATextLayer時,設(shè)置完字體后顯示會模糊.

下面看一下映射關(guān)系.

非Retina:1 Point = 1 x 1 Pixel

Retina:1 Point = 2 x 2 Pixel

由于 Retina 屏一個 Point 映射4個(2 * 2) Pixel,所以 scale為2.

所以這時牽扯到一個屬性:contentsScale

有兩種方案:

方案一 : 使用帶屬性的字符串,這種方法簡單明了.

方案二 : 設(shè)置navigationItem.titleView. 給titleView賦值一個 label, 這樣子的話修改起來都是常規(guī)做法.

iOS修改私有屬性&&成員變量(KVC)

修改私有屬性,是我們?nèi)粘i_發(fā)中常見的一個場景。比如修改三方庫的某個屬性,可三方庫并沒有暴露該屬性在頭文件??偟膩碚f,修改私有屬性,兩種方案:KVC和Runtime。今天這里不介紹原理,只講實操。

總體思路:通過繼承要修改類,拿到要修改的屬性或者成員變量,改變其值,再賦值給該類。

以下舉例,通過子類ZXSonViewController繼承父類ZXParentViewController和,在viewDidLoad方法里做演示。

父類定義了私有屬性name

子類繼承父類,通過KVC修改

此時使用的Api由[setValue: forKey:]換為[setValue:forKeyPath:]

父類使用自定義類一個作為屬性

子類通過[setValue:forKeyPath:] 修改

當(dāng)修改的是成員變量時

子類

由于struct本身并不遵循KVC協(xié)議,但是我們可以轉(zhuǎn)化為NSValue解決

父類使用一個枚舉做成員變量

子類通過五步操作,修改父類成員變量值

截圖如下

看下打印結(jié)果

通過KVC修改私有屬性或者成員變量的方法基本都列舉完了,但注意KVC本身屬于硬編碼形式,容易操作閃退,使用時要做好安全防護(hù)。


網(wǎng)頁標(biāo)題:ios開發(fā)kvc,ios開發(fā)kvc原理
當(dāng)前路徑:http://weahome.cn/article/dsdpejc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部