美文网首页
关于KVO与KVC与Notification与Delegate与

关于KVO与KVC与Notification与Delegate与

作者: 力多 | 来源:发表于2016-11-07 15:11 被阅读0次

    一 Delegate

    1.定义delegate

    .h文件(UITableViewDataSource举例)

    @protocol UITableViewDataSource<NSObject>
    //@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 <NSCoding>
    //delegate需要修饰符weak,如果使用strong会造成循环引用
    @property (nonatomic, weak, nullable) id <UITableViewDataSource> 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与

          本文链接:https://www.haomeiwen.com/subject/wyymuttx.html