1、kvc
kvc很简单就是声明属性时不添加属性的setter方法和getter方法,而用kvc专有的方法进行赋值和取值
例子如下:
@interface Student : NSObject
//声明时不加@property关键字
{
NSString *_name;
NSInteger _age;
}
@end
//重写description方法
@implementation Student
- (NSString *)description {
return [NSString stringWithFormat:@"name is %@,age is %ld",_name,_age];
}
//在 main 函数中执行以下代码
Student *stu = [Student new];
[stu setValue:@"zsz" forKey:@"_name"];
//这里要注意封装基本数据类型,因为要传入的只能是对象
[stu setValue:[NSNumber numberWithInteger:22] forKey:@"_age"];
NSLog(@"%@",[stu description]);
2、KVO
基于kvc的一种技术…
分为以下3步
(1)注册成为观察者
(2)观察者定义kvo的回调
(3)移除观察者
//
// StudentObserver.h
// 阶段小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
@interface StudentObserver : NSObject
@property (nonatomic,strong)Student *student;
//注册成为观察者的方法
- (id)addObserver;
@end
如上,把要进行观察的对象传入观察者里面作为观察者的一个属性(传入的这个对象一定要遵循kvc),顺便声明一个注册成为观察者的方法;
//
// StudentObserver.m
// 阶段小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
@implementation StudentObserver
//以下是注册成为观察者的方法,
- (id)addObserver {
//注意这下面注册时是调用被观察者对象的方法。。。
[self.student addObserver:self forKeyPath:@"_name" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
[self.student addObserver:self forKeyPath:@"_age" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
return self;
}
//以下是重写的回调方法,一旦要观察的对象的属性发生变化,就执行相应的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"_name" ] ) {
NSString *oldName = [change objectForKey:NSKeyValueChangeOldKey];
NSString *newName = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"oldName = %@,newName = %@",oldName,newName);
} else if ([keyPath isEqualToString:@"_age"]) {
NSString *oldAge = [change objectForKey:NSKeyValueChangeOldKey];
NSString *newAge = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"oldAge = %@,newName = %@",oldAge,newAge);
}
}
//以下是移除观察者
- (void)dealloc {
[self.student removeObserver:self forKeyPath:@"_name"];
[self.student removeObserver:self forKeyPath:@"_age"];
}
//以下代码是在主函数中调试kvo的代码
StudentObserver *aStuOb = [StudentObserver new];
aStuOb.student = stu;
aStuOb = [aStuOb addObserver];
[stu setValue:@"zsz2" forKey:@"_name"];
[stu setValue:[NSNumber numberWithInteger:18] forKey:@"_age"];
3、通知
步骤:
1、要发送通知的对象要先声明实现一个方法,可以到通知中心发送一个通知
//.h文件中
@interface Center : NSObject
- (void)sentMessage;
@end
//.m文件中
@implementation Center
- (void)sentMessage {
//创建一个通知对象,在通知中心 把通知发出去
NSNotification *notification = [[NSNotification alloc] initWithName:@"Message" object:self userInfo:[NSDictionary dictionaryWithObject:@"发送了通知" forKey:@"key1"]];
[[NSNotificationCenter defaultCenter] postNotification:notification];
//简便写法
// [[NSNotificationCenter defaultCenter] postNotificationName:@"Message" object:self userInfo:[NSDictionary dictionaryWithObject:@"我发送了通知" forKey:@"key1"]];
}
@end
2、要接收通知的对象,要声明实现一个接收通知的方法,并实现一个回调方法,最后移除通知
//
// People.h
// 通知小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface People : NSObject
-(void)login;//注册监听者接收通知的方法
- (void)aMethod:(NSNotification *)notifi;//回调方法
@end
//
// People.m
// 通知小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import "People.h"
@implementation People
- (void)login {
//先到通知中心注册监听者,说明可以接收怎样的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(aMethod:) name:@"Message" object:nil];
}
//接收到通知要执行的方法
- (void)aMethod:(NSNotification *)notifi {
NSDictionary *dict = [notifi userInfo];//从通知的字典中获取通知内容
NSLog(@"我接收到了它 %@",[dict objectForKey:@"key1"]);
}
//移除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"Message" object:nil];
}
@end
通知与kvo的区别:
KVO只能监听属性的变化,通过NSString类型的属性名来实现,实现了自动监听,当属性值发生变化时,会自动通知观察者,不用在添加代码了。但是观察者得持有被观察者的引用,一边在观察者对象中调用被观察对象的方法,耦合性太高,不利于代码维护。。。。。
通知 就比较灵活,可以监听的内容不局限于属性的变化,还可以对多种多样的状态变化进行监听,(比如,一旦属性发生变化就直接发送一个通知就好。一旦调用了哪个方法也可以发送一个通知,把这个通知在那个方法里调用)缺点是想:需要被观察者自己手动发送通知
利用协议 的 委托模式
建立两个类student和waiter类,waiter遵守协议,如果学生忙就要送餐给学生。如果学生不忙就不用送,学生自己拿
直接通过例子来看
//
// Sent.h
// 委托模式小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol Sent <NSObject>//这是一个送餐协议
- (void)sent;
- (void)noSent;
@end
//
// Waiter.h
// 委托模式小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Sent.h"
@interface Waiter : NSObject <Sent>//waiter遵守这个协议
@end
//
// Waiter.m
// 委托模式小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import "Waiter.h"
@implementation Waiter//waiter实现了这个协议的方法
- (void)sent {
NSLog(@"学生忙,要送餐");
}
- (void)noSent {
NSLog(@"学生不忙,自己拿");
}
@end
//
// Student.h
// 委托模式小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Sent.h"
@interface Student : NSObject
@property (nonatomic,strong)id <Sent>delegate;//这里定义一个代理,一定要遵守这个送餐协议
@property (nonatomic,assign)BOOL busy;//
- (void)isBusy;//是否忙调用传入的代理的协议的方法,相当回调方法
@end
//
// Student.m
// 委托模式小结
//
// Created by 5005 on 15/8/9.
// Copyright (c) 2015年 tmr. All rights reserved.
//
#import "Student.h"
@implementation Student
-(void)isBusy {//通过条件判断使用传入代理的哪个方法
if (self.busy) {
[self.delegate sent];
} else {
[self.delegate noSent];
}
}
@end