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

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)

(0)

相关推荐

  • Objective-C编程中语句和变量的一些编写规范建议

    语句 条件语句 条件语句体应该总被大括号包围.只有一行代码最好也加上,否则会带来安全隐患. 复制代码 代码如下: // 推荐 if (!error) {     return success; } // 不推荐 if (!error)     return success; if (!error) return success; 尤达表达式(Yoda) 不要使用尤达表达式.(名字起源于星球大战中尤达大师的讲话方式,总是用倒装的语序) 复制代码 代码如下: // 推荐 if ([myValue i

  • 简介Objective-C解析XML与JSON数据格式的方法

    解析XML 本文以解析本地XML为例,网络获取到的返回值只需转换成NSData型,解析是同理 需要解析的xml文件如下,users.xml <?xml version="1.0" encoding="UTF-8"?> <AllUsers> <message>用户信息</message> <user> <name>芳仔小脚印</name> <age>10</age&g

  • 简单讲解Objective-C的基本特性及其内存管理方式

    一.OC简介 Oc语言在c语言的基础上,增加了一层最小的面向对象语法,完全兼容C语言,在OC代码中,可以混用c,甚至是c++代码. 可以使用OC开发mac osx平台和ios平台的应用程序. 拓展名:c语言-.c  OC语言.-m  兼容C++.-mm 注:其实c语言和oc甚至任何一门语言都只是我们为了实现一些功能,达到一些效果而采用的工具,抛开语法的差别外,我想最重要的应该是在解决问题的时候考虑的角度和方法不一样而已,然而这也构成了学习一门语言的重要性. 二.语法预览 (1)关键字 基本上所有

  • 举例讲解Objective-C中@property属性的用法

    学过c/c++的朋友都知道,我们定义struct/class的时候,如果把访问限定符(public,protected,private)设置为public的话,那么我们是可以直接用.号来访问它内部的数据成员的.比如 //in Test.h class Test { public: int i; float f; }; 我在main函数里面是可以通过下面的方式来使用这个类的:(注意,如果在main函数里面使用此类,除了要包含头文件以外,最重要的是记得把main.m改成main.mm,否则会报一些奇

  • 理解Objective-C的变量以及面相对象的继承特性

    OC点语法和变量作用域 一.点语法 (一)认识点语法 声明一个Person类: 复制代码 代码如下: #import <Foundation/Foundation.h> @interface Person : NSObject {     int _age;//默认为@protected } - (void)setAge:(int)age; - (int)age; @end Person类的实现: 复制代码 代码如下: #import "Person.h" @impleme

  • 详解Objective-C编程中对设计模式中适的配器模式的使用

    引言 在项目开发中,有时候会遇到这样的一种情景:需要使用以前开发的"一些现存的对象",但是新环境中要求的接口是这些现存对象所不满足的.怎样应对这种迁移的需求?使得可以复用这些对象,以满足新的应用环境,这就是适配器(Adapter)所要解决的问题. 定义 "将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作." 最初的定义出现于<设计模式>(Addison-Wesley,1994). 这个定义应该

  • 详解Objective-C设计模式编程中对备忘录模式的运用

    基本理解 这个模式有三个关键角色:原发器(Originator).备忘录(Memento).看管人(caretaker).三者的基本关系是:原发器创建一个包含其状态的备忘录,并传给看管人.看管人不知道如何与备忘录交互,但会把备忘录放在一个安全之处保管好. 备忘录(Memento):在 不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象回复到原先保存的状态. Originator(发起人):负责创建一个备忘录,用以记录当前时刻它的内部状态,并且可使用恢

  • Objective-C的NSOperation多线程类基本使用指南

    NSOperation 一.NSOperation 1.简介 NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作. NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有2种: 1> Foundation框架提供了两个具体子类直接供我们使用:NSInvocationOperation和NSBlockOperation 2> 自定义子类继承NSOperation,实现内部相应的方法 2.执行操作

  • Objective-C中编程中一些推荐的书写规范小结

    一.类 1. 类名 类名应该以三个大写字母作为前缀(双字母前缀为Apple的类预留) 不仅仅是类,公开的常量.Protocol等的前缀都为相同的三个大写字母. 当你创建一个子类的时候,你应该把说明性的部分放在前缀和父类名的中间. 例如: 如果你有一个 ZOCNetworkClient 类,子类的名字会是ZOCTwitterNetworkClient (注意 "Twitter" 在 "ZOC" 和 "NetworkClient" 之间); 按照这个

  • 浅析Objective-C中分类Category的使用

    无论一个类设计的如何完美,都不可避免的会遇到没有预测到的需求,那怎么扩展现有的类呢?当然,继承是个不错的选择.但是Objective-C提供了一种特别的方式来扩展类,叫Catagory,可以动态的为已经存在的类添加新的行为.这样可以保证类的原原来的基础上,较小的改动就可以增加需要的功能.使用Category对类进行扩展时,不需要访问其源代码,也不需要创建子类,这样我们可以扩展系统提供的类.Category使用简单的方式,实现了类的相关方法的模块化,把不同的类方法分配到不同的分类文件中. 使用Ob

随机推荐