欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

以实例讲解Objective-C中的KVO与KVC机制

程序员文章站 2024-03-06 15:51:14
kvo实例浅析 最近遇到个问题,在处理项目中一个评论界面时,因为直接用的是uiwebview展示评论列表,结果取到的页面上下都有一段cgsize为(320,65)的乱七八...

kvo实例浅析

最近遇到个问题,在处理项目中一个评论界面时,因为直接用的是uiwebview展示评论列表,结果取到的页面上下都有一段cgsize为(320,65)的乱七八糟的广告,十分碍眼.头部广告因很方便的在头部坐标贴上自己的logo解决了,但是尾部的,因为每个页面的评论长短不一,坐标也就不一样,这样就不能给定死坐标去贴logo,思前想后,通过kvo很好的解决了这个问题.
@kvo概述:
kvo,即:key-value observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。
简单的说就是每次指定的被观察的对象的属性被修改后,kvo就会自动通知相应的观察者了。

使用步骤如下:
1. 注册,指定被观察者的属性,
2. 实现回调方法
3. 触发回调方法  
4. 移除观察

代码实例:

复制代码 代码如下:

-(void)viewdidload{ 
 
    // kvo,作为一个观察者,只要属性"contentsize"发生变化,回调方法里面就会通知 
    [_webview.scrollview addobserver:self forkeypath:@"contentsize" options:nskeyvalueobservingoptionnew context:null]; 

 
//  回调方法 
- (void)observevalueforkeypath:(nsstring *)keypath ofobject:(id)object change:(nsdictionary *)change context:(voidvoid *)context 

    if(object == _webview.scrollview && [keypath isequaltostring:@"contentsize"]) 
    { 
        //  得到最大的y坐标 
        cgsize size = _webview.scrollview.contentsize; 
       
        if (size.height > 568.0) { 
             
            // 遮挡广告 
            _hidebottomimage = [[uiimageview alloc] initwithframe:cgrectmake(0, size.height-67, screenwidth, 67)]; 
            _hidebottomimage.image = [uiimage imagenamed:@"banner"]; 
            [_webview.scrollview addsubview:_hidebottomimage]; 
            [_hidebottomimage release]; 
        } 
    } 
    else 
    { 
        //  调用父类的方法 
        [super observevalueforkeypath:keypath ofobject:object change:change context:context]; 
    } 

 
- (void)dealloc{//---->在arc环境下也能调用dealloc方法,只是不需要写[super dealloc] 
 
    // 移除kvo,否则会引起资源泄露  
    [_webview.scrollview removeobserver:self forkeypath:@"contentsize"]; 
    [super dealloc];   
 

上面是针对contentsize属性,其他属性依此类推

kvc
通常,我们都是通过属性的set和get方法来赋值和取值,这里介绍用key-value-coding(kvc)键值编码来给类的属性赋值和取值.
1.基本方式(setvalue:forkey:      valueforkey)

复制代码 代码如下:

//  ---定义一个student类(.m文件无任何操作) 
#import <foundation/foundation.h> 
 
 
@class hmtclass; 
@interface hmtstudent : nsobject{ 
 
    nsstring * _name; 
    
    bool _test; 
    bool _istest; 
    bool test; 
    bool istest; 
 

 
@property (nonatomic,copy)nsstring * name; 
@property (nonatomic,copy)nsstring * sex; 
@property (nonatomic,assign)nsinteger age; 
@property (nonatomic,strong) hmtclass * hmtclass; 
 
@end 
 
//  ---main文件 
hmtstudent * student = [[hmtstudent alloc] init]; 
     
student.hmtclass = [[hmtclass alloc] init]; 
student.name = @"humingtao”;     //  set方法赋值
   
//  kvc赋值    
[student setvalue:@“mawei is dog" forkey:@"name”];  
[student setvalue:@"m" forkey:@"sex"]; 
[student setvalue:@(10) forkey:@"age"]; 
//  取值     
nslog(@"%s__%d__|%@",__function__,__line__,[student valueforkey:@"name"]); 
 
特别注意: 
   我在类里面还定义了4个bool值变量,用来验证kvc访问属性键顺序 
       [student setvalue:@(yes) forkey:@"test”]; 
 
       结果是:_test—>_istest—>test—>istest 

2.键路径访问(用于一个类中属性的属性 setvalue:forkeypath: forkeypath)

复制代码 代码如下:

//  创建一个班级类 
@interface hmtclass : nsobject 
 
@property (nonatomic,copy)nsstring * name; 
 
@end 
 
然后前面第一点中在student类中写了一个班级属性hmtclass 
复制代码 代码如下:
 
hmtclass *hmtclass = [[hmtclass alloc]init]; 
[hmtclass setvalue:@"宇宙一班" forkey:@"name"]; 
[student setvalue:hmtclass forkey:@"hmtclass"]; 
nsstring *hmtclassname = [student valueforkeypath:@"hmtclass.name"]; 
 
//也可以这样存值 
[student setvalue:@"宇宙一班" forkeypath:@"hmtclass.name"]; 
student.hmtclass.name = [student valueforkeypath:@"hmtclass.name"]; 

3.自动封装基本数据类型
我们在student类中添加分数属性 nsinteger number 学号;
复制代码 代码如下:

#import <foundation/foundation.h>   
@class hmtclass;   
@interface hmtstudent : nsobject   
{   
    nsstring *_name;   
 
    nsinteger number;   
}   
@end   
 
[student setvalue:@"100" forkeypath:@"number"];   
nsstring *number = [student valueforkey:@"number"];   

可见用nsstring*类型设置的属性值@"100",而我们的属性是nsinteger类型的,存取都没有问题。 

4.操作集合
在student类中加入数组nsarray,用来表示其他的学生。

复制代码 代码如下:

#import <foundation/foundation.h>   
@class hmtclass;   
@interface hmtstudent : nsobject   
{   
    nsarray *manystudents;   
}   
@end   
           
student *student1 = [[hmtstudent alloc]init];   
student *student2 = [[hmtstudent alloc]init];   
student *student3 = [[hmtstudent alloc]init];   
[student1 setvalue:@"200" forkey:@"number"];   
[student2 setvalue:@"300" forkey:@"number"];   
[student3 setvalue:@"400" forkey:@"number"];   
nsarray *array = [nsarray arraywithobjects:student1,student2,student3,nil];   
[student setvalue:array forkey:@"manystudents"];   
nslog(@"%@",[student valueforkeypath:@"manystudents.number"]);  

打印出来是数组(200,300,400)