C---OCKVC和KVO

KVC、KVO探识(三)KVC你不知道的细节(执行顺序)

2016-03-28  本文已影响379人  Peak_One
前言

今天主要探究一些KVC几个方法的执行顺序。表面浅显的东西,其实也内有乾坤。这点东西,你真的未必懂!

KVC执行顺序

今天主要来分辨一下这几个方法的执行顺序,也许会对你有很大的帮助。

-setter
-getter
-(void)setValue:forKey:
-(id)valueForKey:
+(BOOL)accessInstanceVariablesDirectly//参考KVC、KVO探识(二)

下面看代码示例:(耐心看下去,你会有不一样的收获)
情况一:
model.h

#import <Foundation/Foundation.h>

@interface model : NSObject
@property(nonatomic,copy)NSString *name;
@end

model.m
#import "model.h"

@implementation model

@synthesize name=_name;//如果重写了setter和getter方法,@property就不会生成name属性和_name属性。所以在这里将name和_name,并且手动生成。
 -(NSString *)name{
    NSLog(@"%s",__func__);
    return _name;
}

-(void)setName:(NSString *)name{
    _name=name;
    NSLog(@"%s",__func__);
}

+(BOOL)accessInstanceVariablesDirectly{
    NSLog(@"%s",__func__);
    return [super accessInstanceVariablesDirectly];
//    return YES;
}

-(void)setValue:(id)value forKey:(NSString *)key{
    NSLog(@"%s",__func__);
    [super setValue:value forKey:key];

}

-(id)valueForKey:(NSString *)key{
    NSLog(@"%s",__func__);
    //return nil;
    return [super valueForKey:key];
}

@end

此时在ViewController.m中进行调用:
ViewController.m

#import "ViewController.h"
#import "model.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    model *modell=[[model alloc]init];
    [modell setValue:@"lxh" forKey:@"name"];
    [modell valueForKey:@"name"];
    NSLog(@"%@",modell.name);
}

@end

输出结果如下:

2016-03-28 15:16:07.449 TestKVC[673:12775] -[model setValue:forKey:]
2016-03-28 15:16:11.640 TestKVC[673:12775] -[model setName:]
2016-03-28 15:16:11.640 TestKVC[673:12775] -[model valueForKey:]
2016-03-28 15:16:11.640 TestKVC[673:12775] -[model name]
2016-03-28 15:16:11.640 TestKVC[673:12775] -[model name]
2016-03-28 15:16:11.641 TestKVC[673:12775] lxh

问题:(先思考,后面讲解)
1.为什么没有调用:+(BOOL)accessInstanceVariablesDirectly?
注意:
经过自己打断点测试: [super setValue:value forKey:key];方法中调用了model的setter方法。同理:[super valueForKey:key];方法调用了
model的getter方法。
情况二:
model.h

#import <Foundation/Foundation.h>

@interface model : NSObject
@property(nonatomic,copy)NSString *name;
@end

model.m
#import "model.h"

@implementation model

@synthesize name=_name;
 -(NSString *)name{
    NSLog(@"%s",__func__);
    return _name;
}

-(void)setName:(NSString *)name{
    _name=name;
    NSLog(@"%s",__func__);
}

+(BOOL)accessInstanceVariablesDirectly{
    NSLog(@"%s",__func__);
    return [super accessInstanceVariablesDirectly];
//    return YES;
}

-(void)setValue:(id)value forKey:(NSString *)key{
    NSLog(@"%s",__func__);
    [super setValue:value forKey:key];

}

-(id)valueForKey:(NSString *)key{
    NSLog(@"%s",__func__);
    //return nil;
    return [super valueForKey:key];
}

@end

此时在ViewController.m中进行调用:
ViewController.m

#import "ViewController.h"
#import "model.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    model *modell=[[model alloc]init];
    [modell setValue:@"lxh" forKey:@"_name"];
    [modell valueForKey:@"_name"];
    NSLog(@"%@",modell.name);
}

@end

输出结果如下:

2016-03-28 15:23:43.665 TestKVC[703:15739] -[model setValue:forKey:]
2016-03-28 15:23:48.416 TestKVC[703:15739] +[model accessInstanceVariablesDirectly]
2016-03-28 15:23:57.708 TestKVC[703:15739] -[model valueForKey:]
2016-03-28 15:23:57.708 TestKVC[703:15739] +[model accessInstanceVariablesDirectly]
2016-03-28 15:23:57.709 TestKVC[703:15739] -[model name]
2016-03-28 15:23:57.709 TestKVC[703:15739] lxh

问题:
1.为什么此时没有调用setter、getter方法,而是调用了+[model accessInstanceVariablesDirectly]?
2.为什么第二种情况没有调用setter、getter(现有的)方法,也能输出正确结果?
注意:
经过打断点发现:[super setValue:value forKey:key];方法中调用了+accessInstanceVariablesDirectly这个方法。同理:[super valueForKey:key];方法也调用了+accessInstanceVariablesDirectly。
对比前两种情况,你会感觉很迷惑,但是请坚持住,接着往下看
第三种情况:
model.h

#import <Foundation/Foundation.h>

@interface model : NSObject
@property(nonatomic,copy)NSString *name;
@end

model.m
#import "model.h"

@implementation model

@synthesize name=_name;//如果重写了setter和getter方法,@property就不会生成name属性和_name属性。所以在这里将name和_name,并且手动生成。
 -(NSString *)name{
    NSLog(@"%s",__func__);
    return _name;
}

-(void)setName:(NSString *)name{
    _name=name;
    NSLog(@"%s",__func__);
}

+(BOOL)accessInstanceVariablesDirectly{
    NSLog(@"%s",__func__);
    return [super accessInstanceVariablesDirectly];
//    return YES;
}

-(void)setValue:(id)value forKey:(NSString *)key{
    NSLog(@"%s",__func__);
    [super setValue:value forKey:key];

}

-(void)set_name:(id)name{
    _name=name;
    NSLog(@"%s",__func__);

}

-(id)_name{
    NSLog(@"%s",__func__);
    return _name;
}
-(id)valueForKey:(NSString *)key{
    NSLog(@"%s",__func__);
    //return nil;
    return [super valueForKey:key];
}

@end

此时在ViewController.m中进行调用:
ViewController.m

#import "ViewController.h"
#import "model.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    model *modell=[[model alloc]init];
    [modell setValue:@"lxh" forKey:@"_name"];
    [modell valueForKey:@"_name"];
    NSLog(@"%@",modell.name);
}

@end

输出结果如下:

2016-03-28 15:38:40.383 TestKVC[793:21114] -[model setValue:forKey:]
2016-03-28 15:38:42.575 TestKVC[793:21114] -[model set_name:]
2016-03-28 15:38:43.833 TestKVC[793:21114] -[model valueForKey:]
2016-03-28 15:38:43.834 TestKVC[793:21114] -[model _name]
2016-03-28 15:38:43.834 TestKVC[793:21114] -[model name]
2016-03-28 15:38:43.834 TestKVC[793:21114] lxh

问题:
1.为什么此时调用了setter、getter方法,但是是set_name和_name?
2.为什么此时model的name依旧已经被赋值过了?

对比前两种情况,你会感觉很迷惑,但是请坚持住,接着往下看

看完第三种情况貌似更疯了,不要着急,马上做分析:

分析(现象分析)
1.对比三种情况你会发现:只要调用了setter、getter方法,就不会去调用:+(BOOL)accessInstanceVariablesDirectly方法,反之也是如此。
2.并且赋值阶段都是有[super setValue:value forKey:key];去实现调用的。取值同样是由[super setValue:value forKey:key];去实现的。

分析(深层次)
[super setValue:value forKey:key]方法内部实现赋值有两种方式:一种是调用setter,一种是直接赋值例如:_name=name;
步骤如下:
首先:①如果是采用name去设置的话,[super setValue:value forKey:key]会去查找是否有对应的setName: 方法,如果有,就调用setName:去进行赋值。
如果没有(例如key:_name)则会调用:+(BOOL)accessInstanceVariablesDirectly方法去进行匹配(注意此时该方法的返回值默认是Yes,只有YES才去匹配name和_name)

上一篇下一篇

猜你喜欢

热点阅读