关于KVO与KVC与Notification与Delegate与Block的简单整理

一 Delegate

1.定义delegate

.h文件(UITableViewDataSource举例)

@protocol UITableViewDataSource
//@required是必须实现的方法,不实现程序会crash。
@required

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
//@optional中的方法,可实现可不实现。
@optional

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;              // Default is 1 if not implemented
.....
@end
@interface UITableView : UIScrollView 
//delegate需要修饰符weak,如果使用strong会造成循环引用
@property (nonatomic, weak, nullable) id  dataSource;
@end

在定义文件定义了delegate后在父视图的.m文件里实现方法

-(void)viewDidLoad{
tableview.DataSource=self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 0;
}

delegate相当于A视图需要某项数据,该项数据由B提供,所以A视图提供一个方法给B来实现提供数据这一行为。

二 Block

block大致相当于delegate的另一种形式,它比delegate更加直观,可以将需要实现的内容放到一起,更加直观的观察。
block的大致写法

//  返回数据类型(^方法名字)(需要数据);
@property (nonatomic,copy)void(^testBlock)(void);//属性需要声明为copy
//调用
[self setTestBlock:^ {
      
}];
//用typedef定义
typedef CGFloat(^TestBlock)(int i);
@property (nonatomic,copy)TestBlock testBlock;
//调用
[self  setTestBlock :^CGFloat(int *i){
        return 1.0f;
}];
//方法中定义 (返回数据类型(^)(需要数据)方法名称;
-(void)testBlock:(void(^)(NSString *test))testBlock;
//调用
[self testBlock:^(NSString *test) {
        
}];

使用block时需要注意不要造成循环引用,上述创建的block中,self持有了该block,如果在block里有使用了self,这样就会造成self持有block,block持有self。造成循环引用。这时候需要将self __weak。

__weak typeof(self) weakSelf=self;
[self setTestBlock:^ {
      [weakSelf test];
}];

如果是另一个文件定义的block,使用self则不需要__weak;

Test *test=[[Test alloc]init];
[test setTestBlock:^ {
      [self test];
}];

需要多次使用self时则还需要添加__strong

__weak typeof(self) weakSelf=self;
[self setTestBlock:^ {
__strong typeof(weakSelf) strongSelf=weakSelf;
      [strongSelf test];
      [strongSelf test2];
}];

这样做是避免在使用block的过程中weakSelf变成nil。

三 Notification

Notification是iOS的消息通知机制,和delegate类似,但是delegate比Notification调用前的准备复杂,delegate需要先声明委托的方法才可以使用,而Notification则只需要注册消息以及发送消息。
以下是使用Notification的主要方法。

//通常使用defaultCenter来发送消息。
  [[NSNotificationCenter defaultCenter] postNotificationName:(NSString *)aName object:(nullable id)anObject;];
//其他方法
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
//这三个方法的区别在于他的参数
//object参数我理解为这个消息是以什么名义发送的,例如写self,就是以发送该消息的文件的名义发送,这个参数在后面的接收消息时会用到。
//userInfo可以传递你想要传递给消息接收者的内容。

注册消息的方法

[[NSNotificationCenter defaultCenter] addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObjec];
//name为接收这个name发出的消息,object同理.
//接收到消息后会调用selector方法。
//name为nil,object不为nil则接收来自object的所有消息。
//object为nil,name不为nil,则接收名字为name的所有消息。
//都为nil则接收系统所有发出的消息。
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;

四 KVC

KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。在平时使用的时候其实.出来就好,KVC主要是配合归档和解档使用,配合runtime来动态获取model的属性。例如:

// 遍历模型中成员变量 
unsigned int outCount = 0; 
Ivar *ivars = class_copyIvarList([self class], &outCount); 
for (int i = 0 ; i < count; i++) { 
     Ivar ivar = ivars[i]; // 成员变量名称
     const char *name = ivar_getName(ivar);;// 获取出来的是`_`开头的成员变量名,需要截取`_`之后的字符串 
     NSString *strName = [NSString stringWithUTF8String:name];
     strName = [strName substringFromIndex:1]; 
     id value = [self valueForKey:strName];//利用KVC获取值
     // 归档  [encoder encodeObject:value forKey:strName];
     //解档   
     // id value = [decoder decodeObjectForKey:strName];
     //利用KVC对属性赋值
     //[self setValue:value forKey:strName];
} 
free(ivars);

五 KVO

Key-Value Observing (KVO) 建立在 KVC 之上,它能够观察一个对象的 KVC key path 值的变化。主要用于观察属性的变化.
例如

@interface TestModel : NSObject {  
    float test;  
}  
@end  
@implementation TestModel  
@end  

观察

TestModel *test=[[TestModel alloc]init];
[test setValue:@"10.0" forKey:@"test"];  
//NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
//NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
//NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
//NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
//context 需要传入的值(需要转换)
[test addObserver:self forKeyPath:@"test" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];  
  

每次观察对象改变会调用

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context  
{  
   //判断keyPath,做要做的,object为添加观察的对象,例如test添加了观察则object为test。
}  
//使用后需要移除监听
-(void)delloc{
    [test removeObserver:self forKeyPath:@"test"];
}

你可能感兴趣的:(关于KVO与KVC与Notification与Delegate与Block的简单整理)