2109:507] My son's girl_friend_name change from mimi to libinbin ... That's OK? :(
2014-07-06 20:11:26.761 k[2109:507] My love girl is fanbinbin ... Does baba know?
爸爸监管的不错,可是儿子不高兴喽。hack儿子如何能让老爸如此侵犯隐私啊?咋办呢?不自动传递变更通知不就结了!为了实现手动通知,需要重写Son的类方法+automaticallyNotifiesObserversForKey,来告知obj-c你不想自动通知观察者自己的变化,注意是类方法哦!可以通过对特定的键名返回NO来完成:
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if([key isEqualToString:@"girl_friend_name"])
return NO;
return YES;
}
在Son类的实现中加入以上类方法,重新编译运行:
apple@kissAir: objc_src$./k
2014-07-06 20:37:36.726 k[2180:507] My love girl is lili ... Does baba know?
2014-07-06 20:37:36.729 k[2180:507] Yes , It's first time to induction son's girl_name!!!
2014-07-06 20:37:36.729 k[2180:507] My love girl is mimi ... Does baba know?
2014-07-06 20:37:36.730 k[2180:507] My love girl is libinbin ... Does baba know?
老爸”感应“不到喽!但是这样长了老爸会怀疑的啦,肿么宝贝儿子从不谈恋爱呢?这个不行哦!于是乎聪明的hack儿子可以再手动的通知老爸篡改后的内容啊!具体为:在Son属性写者方法的变化之前调用-willChangeva lueForKey,然后在变化之后调用-didChangeva lueForKey,重新改写写者方法吧,修改后完整代码如下:
#import
#define msg(...) NSLog(__VA_ARGS__)
#define mki(x) [NSNumber numberWithInt:x]
@interface Son:NSObject{
NSString *girl_friend_name;
}
//在属性默认为atomic的情况下,如果自定义写者方法必须同时自定义读者方法,
//或者将属性改为nonatomic模式。
@property(nonatomic) NSString *girl_friend_name;
-(void)think;
-(void)fall_in_love_with:(NSString *)girl_name;
@end
@implementation Son
@synthesize girl_friend_name;
-(void)fall_in_love_with:(NSString *)girl_name{
self.girl_friend_name = girl_name;
}
-(void)think{
msg(@"My love girl is %@ ... Does baba know?",girl_friend_name);
}
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if([key isEqualToString:@"girl_friend_name"])
return NO;
return YES;
}
-(void)setGirl_friend_name:(NSString *)name{
[self willChangeva lueForKey:@"girl_friend_name"];
//让老爸以为自己和女学霸谈恋爱哦
girl_friend_name = @"女学霸";
[self didChangeva lueForKey:@"girl_friend_name"];
//恢复本色吧,BAD BOY... :)
girl_friend_name = name;
}
@end
@interface Baba:NSObject{
Son *son;
}
@property Son *son;
@end
@implementation Baba
@synthesize son;
-(id)initWithSon:(Son *)son_v{
self = [super init];
if(self){
son = son_v;
[son addObserver:self forKeyPath:@"girl_friend_name" \
options:(NSKeyValueObservingOptionNew|\
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionInitial) \
context:nil];
}
return self;
}
-(void)observeva lueForKeyPath:(NSString *)key_path \
ofObject:(id)obj change:(NSDictionary *)change \
context:(void *)context{
NSString *old_name = [change objectForKey:NSKeyValueChangeOldKey];
NSString *new_name = [change objectForKey:NSKeyValueChangeNewKey];
if(!old_name){
//NSKeyValueObservingOptionInitial选项的作用,第一次hook会发一次消息
//以后每次更改会发一次消息。
msg(@"Yes , It's first time to induction son's girl_name!!!");
}else{
if([new_name isEqualToString:@"libinbin"]){
[obj fall_in_love_with:@"fanbinbin"];
}
msg(@"My son's %@ change from %@ to %@ ... That's OK? :(",\
key_path,old_name,new_name);
}
}
-(void)dealloc{
[son removeObserver:self forKeyPath:@"girl_friend_name"];
son = nil;
//[super dealloc];
}
@end
int main(int argc