iOS觀察者模式學(xué)習(xí)
(1)KVC與KVO簡(jiǎn)介
- KVC
KVC(Key-value coding)是一種間接更改對(duì)象狀態(tài)的方式。
官方文檔描述:
Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables. In essence, key-value coding defines the patterns and method signatures that your application’s accessor methods implement.
- KVC的作用
通過(guò)鍵值的方式訪問(wèn)對(duì)象或者修改對(duì)象的值
比如:NSString *name = [car valueForKey: @"name"];通過(guò)-valueForKey:獲取對(duì)象,它會(huì)先查找以參數(shù)名命名(格式為-key或-isKey)的getter方法,對(duì)于上面的調(diào)用,valueForKey:會(huì)先尋找-name方法。如果沒(méi)有這樣的getter方法,它將會(huì)在對(duì)象內(nèi)尋找名稱格式為_key或key的實(shí)例變量。通過(guò)使用KVC,沒(méi)有相關(guān)getter方法也能獲取對(duì)象,不需要通過(guò)對(duì)象指針來(lái)直接訪問(wèn)實(shí)例變量。
- KVC的優(yōu)缺點(diǎn)
1.KVC可以輕松處理集合類。(如:NSArray)
2.KVC沒(méi)有相關(guān)getter方法也能獲取對(duì)象,不需要通過(guò)對(duì)象指針來(lái)直接訪問(wèn)實(shí)例變量
3.簡(jiǎn)化代碼
4.KVC需要解析字符串,速度比較慢
5.編譯器無(wú)法進(jìn)行錯(cuò)誤檢查
- KVO
KVO(Key-value Observing)是基于KVC的,一種監(jiān)聽(tīng)方式,也就是所謂的觀察者模式。
官方文檔描述:
Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application.
(2)KVC代碼實(shí)現(xiàn)
//1.setValue: forKey
[car setValue: @"奔馳" forKey: @"name"];
[car setValue: [NSNumber numberWithFloat: 80] forKey: @"speed"];
[car setValue: @"黑色" forKey: @"carPaint"];
//1.valueForKey
NSString *name = [currentCar valueForKey: @"name"];
NSNumber *speed = [currentCar valueForKey: @"speed"];
NSString *carPaint = [currentCar valueForKey: @"carPaint"];
//2.setValue:forKeyPath
[car setValue: [NSNumber numberWithFloat: 40] forKeyPath: @"engine.horsepower"];
self.showCarDetail.text = [self showCarDetail: car];
//2.valueForKeyPath
NSNumber *horsepower = [currentCar valueForKeyPath: @"engine.horsepower"];
//3.整體操作:訪問(wèn)數(shù)組,如果使用某個(gè)鍵值來(lái)訪問(wèn)一個(gè)NSArray數(shù)組,它實(shí)際上會(huì)查詢相應(yīng)數(shù)組中的每個(gè)對(duì)象,然后將查詢結(jié)果大包到另一個(gè)數(shù)組并返回,但是不能直接在建路徑中索引這些數(shù)組,如:tires[0].pressure
NSArray *pressures = [currentCar valueForKeyPath: @"tires.pressure"];
NSLog(@"%@", pressures);
//4.快速運(yùn)算@count,@sum,@avg,@min,@max,@distinctUnionOfObjects
NSNumber *count = [currentCar valueForKeyPath: @"tires.@count"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取數(shù)組數(shù)量
NSNumber *sum = [currentCar valueForKeyPath: @"tires.@sum.pressure"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取每個(gè)數(shù)組里面的pressure值,求和
NSNumber *avg = [currentCar valueForKeyPath: @"tires.@avg.pressure"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取每個(gè)數(shù)組里面的pressure值,求平均值
NSNumber *min = [currentCar valueForKeyPath: @"tires.@min.pressure"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取每個(gè)數(shù)組里面的pressure值,找出最小值
NSNumber *max = [currentCar valueForKeyPath: @"tires.@max.pressure"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取每個(gè)數(shù)組里面的pressure值,找出最大值
NSArray *tireType = [currentCar valueForKeyPath: @"tires.@distinctUnionOfObjects.pressure"]; //對(duì)左邊鍵值返回?cái)?shù)組操作,獲取每個(gè)數(shù)組里面的pressure值,去掉重復(fù)的值,返回一個(gè)包含所有不重復(fù)值的數(shù)組
NSLog(@"TiresCount: %@ Sum: %@, Avg: %@, Min: %@, Max: %@, TireType: %@", count, sum, avg, min, max, tireType);
//5.批處理
//字典里面不能為nil,如果返回值有nil,則KVC會(huì)自己處理,將返回[NSNull null]表示nil
//<null>和(null)的區(qū)別:前者是[NSNull null]對(duì)象,而后者是正真的nil。
NSArray *keys = [NSArray arrayWithObjects: @"make", @"modelYear", @"numberOfDoors", nil];
NSDictionary *carValues = [currentCar dictionaryWithValuesForKeys: keys];
NSLog(@"%@", carValues);
//6.nil處理
//可以自己運(yùn)行一下,重寫和沒(méi)有重寫setNilValueForKey:方法的代碼
[currentCar setValue: nil forKey: @"speed"];
NSLog(@"carSpeed: %@", [currentCar valueForKey: @"speed"]);
//7.處理未定義的值
[currentCar setValue: [NSNumber numberWithFloat: 1500] forKey: @"mileage"];
[currentCar setValue: [NSNull null] forKey: @"price"];
[currentCar setValue: nil forKey: @"capacity"];
NSLog(@"Mileage: %@ Price: %@, Capacity: %@", [currentCar valueForKey: @"mileage"], [currentCar valueForKey: @"price"], [currentCar valueForKey: @"capacity"]);
//8.KVC有自動(dòng)裝箱的功能,當(dāng)使用valueForKey時(shí),它自動(dòng)將標(biāo)量值(int,float,struct...)放入NSNumber或NSValue中;當(dāng)使用setValueForKey,它自動(dòng)將標(biāo)量值從這些對(duì)象取出。
(3)KVO代碼實(shí)現(xiàn)
//應(yīng)該在監(jiān)聽(tīng)者里添加監(jiān)聽(tīng),而不是在被監(jiān)聽(tīng)者里添加監(jiān)聽(tīng)
//在被監(jiān)聽(tīng)者添加監(jiān)聽(tīng)會(huì)造成循環(huán)引用的問(wèn)題
car = [[Car alloc] init];
[car addObserver: self forKeyPath: @"carPaint" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString: @"carPaint"]) {
NSLog(@"%@", [change objectForKey: @"new"]); //修改之后的值
self.showCarDetail.text = [NSString stringWithFormat: @"車的顏色是%@", [change objectForKey: @"new"]];
}
}
- (void)dealloc {
//監(jiān)聽(tīng)者應(yīng)該是self,被監(jiān)聽(tīng)者是car
[car removeObserver: self forKeyPath: @"carPaint"];
}
(4)Demo展示:
