iOS開發(fā)經驗(2)

目錄

  1. KVC
  2. 觀察者模式:KVO與通知
  3. 精度問題
  4. 三目運算符
  5. 點語法
1. KVC(Key-value coding)鍵值編碼臼朗。用字符串動態(tài)去操作對象

其實現(xiàn)方法是使用字符串描述要更改的對象狀態(tài)部分农猬。通過Key名直接訪問對象的屬性,或者給對象的屬性賦值帖鸦。這樣就可以在運行時動態(tài)在訪問和修改對象的屬性抄瓦。而不是在編譯時確定。

所有的對象都可以使用KVC
鍵統(tǒng)一是字符串痕檬,而值是不支持基本數據類型的冤寿,必須將值轉換為NSNumber或者NSValue類型

操作對象的屬性和對象屬性的屬性,訪問變量的屬性,即使該屬性沒有get,set方法也可以調用

Human *human = [[Human alloc]init];       
//將name屬性設置為"holydancer"       
[human setValue:@"holydancer" forKey:@"name"];
//將human中的name屬性取出  
NSString *nameOfHuman=[human valueForKey:@"name"];

KVC集合運算符

    ProductModel *model = [[ProductModel alloc]init];
    model.name = @"iMac";
    model.price = @18888;
    ProductModel *model1 = [[ProductModel alloc]init];
    model1.name = @"iphone";
    model1.price = @6999;
    NSArray *array = @[model,model1];

簡單類型的集合操作符:返回 strings, numbers, dates,簡單集合操作符作用于 array 或者 set 中相對于集合操作符右側的屬性青伤。包括 @avg, @count, @max, @min, @sum.

NSString *name = [array valueForKeyPath:@"@count"];//返回集合中對象總數的 NSNumber 對象督怜。操作符右邊沒有鍵路徑。
NSNumber  *price_max = [array valueForKeyPath:@"@max.price"];//比較由操作符右邊的鍵路徑指定的屬性值狠角,并返回比較結果的最大值号杠。最大值由指定的鍵路徑所指對象的 compare: 方法決定
NSString *price_min = [array valueForKeyPath:@"@min.price"];//返回的是集合中的最小值
NSNumber  *price_sum = [array valueForKeyPath:@"@sum.price"];//屬性值的總和
NSNumber  *price_avg = [array valueForKeyPath:@"@avg.price"];//轉換為 double, 計算其平均值,返回該平均值的 NSNumber 對象丰歌。當均值為 nil 的時候姨蟋,返回 0.

提示:你可以簡單的通過把 self 作為操作符后面的 key path 來獲取一個由 NSNumber 組成的數組或者集合的總值,例如對于數組 @[@(1), @(2), @(3)] 可使用 valueForKeyPath:@"@max.self" 來獲取最大值立帖。

NSLog(@"%@,%@,%@,%@,%@",name,price_max,price_min,price_sum,price_avg);

對象操作符眼溶,返回 NSArray 對象實例:對象操作符包括 @distinctUnionOfObjects 和 @unionOfObjects, 返回一個由操作符右邊的 key path 所指定的對象屬性組成的數組。其中 @distinctUnionOfObjects 會對數組去重晓勇,而 @unionOfObjects 不會堂飞。

    NSArray *unionOfObjects = [array valueForKeyPath:@"@unionOfObjects.name"]; // 1.
    NSArray *distinctUnionObjects = [array valueForKeyPath:@"@distinctUnionOfObjects.name"];  //2.
    NSLog(@"%@,%@",unionOfObjects,distinctUnionObjects);

數組和集合操作符,返回的是一個 array 或者 set 對象
數組和集合操作符作用對象是嵌套的集合绑咱,也就是說绰筛,是一個集合且其內部每個元素是一個集合。數組和集合操作符包括 @distinctUnionOfArrays描融,@unionOfArrays铝噩,@distinctUnionOfSets:
@distinctUnionOfArrays / @unionOfArrays 返回一個數組,其中包含這個集合中每個數組對于這個操作符右面指定的 key path 進行操作之后的值窿克。 distinct 版本會移除重復的值骏庸。
@distinctUnionOfSets 和 @distinctUnionOfArrays 差不多, 但是它期望的是一個包含著 NSSet 對象的 NSSet ,并且會返回一個 NSSet 對象让歼。因為集合不能包含重復的值敞恋,所以它只有 distinct 操作。

NSArray *array1 = @[model,model1];
NSArray *totalArray = @[array,array1];
NSArray *distinctUnionOfArrays = [totalArray valueForKeyPath:@"@distinctUnionOfArrays.name"];
NSArray *unionOfArrays = [totalArray valueForKeyPath:@"@unionOfArrays.name"];
NSLog(@"%@,%@",distinctUnionOfArrays,unionOfArrays);

注意: 如果操作符右側 key path 指定的對象為 nil谋右,那么返回的數組中會包含 NSNull 對象.

  • 四個主要方法
    必須手動將值類型轉換成NSNumber或者NSValue類型硬猫,才能設置為value
- (void)setValue:(nullable id)value forKey:(NSString *)key; 
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

valueForKey:總是返回一個id對象,如果原本的變量類型是值類型或者結構體,返回值會封裝成NSNumber或者NSValue對象啸蜜。

- (nullable id)valueForKey:(NSString *)key; 
- (nullable id)valueForKeyPath:(NSString *)keyPath; 
  • 嵌套數據,KEY為數組或者字典

    • 對于有序的容器坑雅,可以用下面的方法:
       - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    
    • 對于無序的容器,可以用下面的方法:
      - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
      
  • 鍵路徑:嵌套數據中衬横,使用KeyPath

  • KVC中處理異常情況

    • 如果某對象有一個常用數據類型裹粤,比如bool,在用setvalue:設置value的時候蜂林,需要實現(xiàn) setNilValueForKey:(NSString *)key
  • 在用set value: 設置value的時候,如果該對象不存在該屬性遥诉,比如bool,需要實現(xiàn) - (void)setValue:(id)value forUndefinedKey:(NSString *)key

  • KVC使用場景

    • 動態(tài)地取值和設值:利用KVC動態(tài)的取值和設值是最基本的用途了噪叙。
  • 用KVC來訪問和修改私有變量:利用KVC可以隨意修改一個對象的屬性和變量(即使是私有變量)
    對于類里的私有屬性矮锈,Objective-C是無法直接訪問的,但是KVC是可以的睁蕾。

  • Model和字典轉換

  • 利用KVC集合運算符苞笨,KVC可以通過運算符層次查找對象的屬性;KVC獲取值不僅可以返回一個數據子眶,還可以將某一個屬性的所有值瀑凝,數據歸類出來(B不一定是類,也可以是數組)

  • 利用KVC可以修改系統(tǒng)的只讀變量臭杰,修改一些控件的內部屬性
    這也是iOS開發(fā)中必不可少的小技巧粤咪。眾所周知很多UI控件都由很多內部UI控件組合而成的,但是Apple度沒有提供這訪問這些空間的API硅卢,這樣我們就無法正常地訪問和修改這些控件的樣式射窒。而KVC在大多數情況可下可以解決這個問題。最常用的就是個性化UITextField中的placeHolderText了将塑。

因為數據造成crash的原因大概幾點:

  1. 使用字面量創(chuàng)建數組脉顿、字典,valuenil
  2. 使用KVC方法給數組字典賦值為nil
  3. null發(fā)送方法点寥。其他的諸如null的判斷方法及給控件賦值都不會引起crash艾疟。
2. 觀察者模式:KVO與通知

iOS的一種設計模式, 觀察者設計模式敢辩,依賴于 Objective-C 強大的 Runtime蔽莱。觀察者模式包含:

1.通知機制(notification)
2.KVO機制【可參考iOS--KVO的實現(xiàn)原理與具體應用】

  • 通知機制:
    委托機制是代理“一對一”的對象之間的通信,而通知機制是廣播“一對多”的對象之間的通信戚长。
//A類獲取通知中心,并發(fā)送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"statusBarHidden" object:nil userInfo:dic];
//B類注冊通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarHidden:) name:@"statusBarHidden" object:nil];
//釋放所有通知
- (void)removeObserver:(id)observer;
//釋放名稱為aName的通知
- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;
  • KVO
    KVO提供一種機制盗冷,指定一個被觀察對象,當對象某個屬性發(fā)生更改時同廉,對象會獲得通知仪糖,并作出相應處理柑司。KVO這種編碼方式使用起來很簡單,很適用與model修改后锅劝,引發(fā)的UIVIew的變化這種情況攒驰,當更改屬性的值后,監(jiān)聽對象會立即得到通知故爵;當指定的對象的屬性被修改后,對象就會接受到通知玻粪,****前提是執(zhí)行了setter方法、或者使用了KVC賦值****诬垂。
    當指定的對象的屬性被修改后劲室,則對象就會接受到通知。簡單的說就是每次指定的被觀察的對象的屬性被修改后结窘,KVO就會自動通知相應的觀察者了痹籍。

原理:

  • 當一個object有觀察者時,動態(tài)創(chuàng)建這個object的類的子類
  • 對于每個被觀察的property晦鞋,重寫其set方法
  • 在重寫的set方法中調用- willChangeValueForKey:和- didChangeValueForKey:通知觀察者
  • 當一個property沒有觀察者時,刪除重寫的方法
  • 當沒有observer觀察任何一個property時棺克,刪除動態(tài)創(chuàng)建的子類
    • 注冊悠垛,指定被觀察者的屬性
[objc addObserver:self forKeyPath:@"title" options:
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
  • 實現(xiàn)回調方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{}
  • 移除觀察
[self removeObserver:self forKeyPath:@"title" context:nil];
  • 兩者區(qū)別:
    notification比KVO多了發(fā)送通知的一步。兩者都是一對多娜谊,但是對象之間直接的交互确买,notification明顯多,需要notificationCenter來做為中間交互纱皆。
    notification的優(yōu)點是監(jiān)聽不局限于屬性的變化湾趾,還可以對多種多樣的狀態(tài)變化進行監(jiān)聽,監(jiān)聽范圍廣派草,例如鍵盤搀缠、前后臺等系統(tǒng)通知的使用也更顯靈活方便.
3. 精度問題
  • 原因:
    NSNumberdescription方法不夠嚴謹,在調用NSNumber的description方法打印數值時近迁,會發(fā)生精度損失艺普。
  • 建議 :
    • 如果是double類型,處理精度有關的數據用double鉴竭。建議把NSNumber轉換成double再進行輸出(NSString)或計算(CGFloat)歧譬;
    • 有關浮點型數據,后臺傳字符串的格式搏存,防止丟失精度.
 NSNumber *value=dic[@"number"];
 NSLog(@"value:%@", value);

輸出:value:81.59999999999999
如果是double類型瑰步,建議把NSNumber轉換成double再進行輸出或計算 。

CGFloat numberValue = [self doubleValue];
NSString *value=[NSString stringWithFormat:@"%g",[dic[@"number"] doubleValue]];
4. 三目運算符
  • 基本格式 : (關系表達式) ? 表達式1 : 表達式2;
  • 執(zhí)行流程 : 關系表達式為 真 返回表達式1 關系表達式為假 返回表達式2
    int num1=8,num2=3,result=0;
    result= num1>num2?num1:num2;
    //因為num1>num2 成立  所以最后結果為num1的值
5. 點語法
  • 點語法的本質還是方法調用,當使用點語法時璧眠,編譯器會自動展開成相應的方法,而不是訪問成員變量.
  • 切記點語法的本質是轉換成相應的對settergetter方法調用,如果沒有setget方法,則不能使用點語法缩焦。
  • 不要在gettersetter方法中使用本屬性的點語法
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末读虏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子舌界,更是在濱河造成了極大的恐慌掘譬,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呻拌,死亡現(xiàn)場離奇詭異葱轩,居然都是意外死亡,警方通過查閱死者的電腦和手機藐握,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門靴拱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人猾普,你說我怎么就攤上這事袜炕。” “怎么了初家?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵偎窘,是天一觀的道長。 經常有香客問我溜在,道長陌知,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任掖肋,我火速辦了婚禮仆葡,結果婚禮上,老公的妹妹穿的比我還像新娘志笼。我一直安慰自己沿盅,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布纫溃。 她就那樣靜靜地躺著腰涧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪紊浩。 梳的紋絲不亂的頭發(fā)上南窗,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機與錄音郎楼,去河邊找鬼万伤。 笑死,一個胖子當著我的面吹牛呜袁,可吹牛的內容都是我干的敌买。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼阶界,長吁一口氣:“原來是場噩夢啊……” “哼虹钮!你這毒婦竟也來了聋庵?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤芙粱,失蹤者是張志新(化名)和其女友劉穎祭玉,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體春畔,經...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡脱货,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了律姨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片振峻。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖择份,靈堂內的尸體忽然破棺而出扣孟,到底是詐尸還是另有隱情,我是刑警寧澤荣赶,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布凤价,位于F島的核電站,受9級特大地震影響拔创,放射性物質發(fā)生泄漏料仗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一伏蚊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧格粪,春花似錦躏吊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疆导,卻和暖如春赁项,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澈段。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工悠菜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人败富。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓悔醋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親兽叮。 傳聞我的和親對象是個殘疾皇子芬骄,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內容

  • KVC(Key-value coding)鍵值編碼猾愿,單看這個名字可能不太好理解。其實翻譯一下就很簡單了账阻,就是指iO...
    黑暗中的孤影閱讀 49,686評論 74 441
  • KVC(Key-value coding)鍵值編碼蒂秘,單看這個名字可能不太好理解。其實翻譯一下就很簡單了淘太,就是指iO...
    朽木自雕也閱讀 1,552評論 6 1
  • KVC(Key-value coding)鍵值編碼姻僧,單看這個名字可能不太好理解。其實翻譯一下就很簡單了琴儿,就是指iO...
    Fendouzhe閱讀 671評論 0 6
  • KVC簡單介紹 KVC(Key-value coding)鍵值編碼负间,就是指iOS的開發(fā)中蛤育,可以允許開發(fā)者通過Key...
    公子無禮閱讀 1,387評論 0 6
  • 坐在公交車上散休,拿著手機讀著白夜行,心里卻在想肄渗,十年前的今天我一定不會想到钉鸯,以后會做著一份平凡的工作,拿著平凡的收入...
    瓶瓶瓶子_閱讀 180評論 0 1