以实例讲解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)