在iOS開(kāi)發(fā)中,蘋(píng)果提供了許多機(jī)制給我們進(jìn)行回調(diào)。KVO(key-value-observing)是一種十分有趣的回調(diào)機(jī)制总滩,在某個(gè)對(duì)象注冊(cè)監(jiān)聽(tīng)者后俺驶,在被監(jiān)聽(tīng)的對(duì)象發(fā)生改變時(shí)幸逆,對(duì)象會(huì)發(fā)送一個(gè)通知給監(jiān)聽(tīng)者,以便監(jiān)聽(tīng)者執(zhí)行回調(diào)操作暮现。最常見(jiàn)的KVO運(yùn)用是監(jiān)聽(tīng)scrollView的contentOffset屬性还绘,來(lái)完成用戶(hù)滾動(dòng)時(shí)動(dòng)態(tài)改變某些控件的屬性實(shí)現(xiàn)效果,包括漸變導(dǎo)航欄栖袋、下拉刷新控件等效果拍顷。
http://jbcdn2.b0.upaiyun.com/2015/12/36a1f0f0ac4af124dbdb65895b2d0fc9.gif
使用
KVO的使用非常簡(jiǎn)單,使用KVO的要求是對(duì)象必須能支持kvc機(jī)制——所有NSObject的子類(lèi)都支持這個(gè)機(jī)制塘幅。拿上面的漸變導(dǎo)航欄做昔案,我們?yōu)閠ableView添加了一個(gè)監(jiān)聽(tīng)者controller,在我們滑動(dòng)列表的時(shí)候电媳,會(huì)計(jì)算當(dāng)前列表的滾動(dòng)偏移量踏揣,然后改變導(dǎo)航欄的背景色透明度。
<pre>//添加監(jiān)聽(tīng)者
[self.tableView addObserver: self forKeyPath: @"contentOffset" options: NSKeyValueObservingOptionNew context: nil];
/**
- 監(jiān)聽(tīng)屬性值發(fā)生改變時(shí)回調(diào)
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
CGFloat offset = self.tableView.contentOffset.y;
CGFloat delta = offset / 64.f + 1.f;
delta = MAX(0, delta);
[self alphaNavController].barAlpha = MIN(1, delta);
}
</pre>
毫無(wú)疑問(wèn)匾乓,kvo是一種非常便捷的回調(diào)方式捞稿,但是編譯器是怎么完成監(jiān)聽(tīng)這個(gè)任務(wù)的呢?先來(lái)看看蘋(píng)果文檔對(duì)于KVO的實(shí)現(xiàn)描述
Automatic key-value observing is implemented using a technique called isa-swizzling… When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class ..
簡(jiǎn)要的來(lái)說(shuō),在我們對(duì)某個(gè)對(duì)象完成監(jiān)聽(tīng)的注冊(cè)后娱局,編譯器會(huì)修改監(jiān)聽(tīng)對(duì)象(上文中的tableView)的isa指針彰亥,讓這個(gè)指針指向一個(gè)新生成的中間類(lèi)。從某個(gè)意義上來(lái)說(shuō)铃辖,這是一場(chǎng)騙局剩愧。
<pre>typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id</pre>
KVO使用三步走:
(1)注冊(cè)成為觀察者
(2)觀察者定義KVO的回調(diào)
(3)移除觀察者
來(lái)點(diǎn)實(shí)際的,還得上代碼:
KVOClass接口:
<pre>
import
@interface KVOClass : NSObject
@property(strong,nonatomic) NSString * name;
@end</pre>
KVOClass實(shí)現(xiàn)
<pre>#import "KVOClass.h"
@implementation KVOClass
//在init注冊(cè)觀察者
-(id) init
{
if (self = [super init]) {
[self addObserver:self
forKeyPath:@"name"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:@"name"];
}
return self;
}
//重寫(xiě)觀察方
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == @"name") {
NSLog(@"name被改變啦娇斩!");
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
//移除觀察者
-(void) dealloc
{
[self removeObserver:self forKeyPath:@"name"];
[super dealloc];
}
@end</pre>
待續(xù)仁卷。。犬第。锦积。。歉嗓。丰介。。鉴分。哮幢。。志珍。橙垢。。