kvc kvo
观察者模式
1. 概述
有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
2. 解决的问题
将一个系统分割成一些相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
【通知中心】
//注册一个观察者,从现在开始,self开始监听IWillKillYou的这个广播,只要这个工程中任意一个地方发送这个广播,self都能响应shasha。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shasha:) name:@"IWillKillYou" object:nil];
//取消观察者身份
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"IWillKillYou" object:nil];
//发送的广播,只要是这个广播的观察者,都能收到广播,然后触发方法,没有个数限制
[[NSNotificationCenter defaultCenter] postNotificationName:@"IWillKillYou" object:str];
//视频播放完成时,系统会自动发送这个广播(自动放完,或者用户手动结束都会响应)
MPMoviePlayerPlaybackDidFinishNotification
【KVC】
//设置和获取成员变量的值(不管是公开还是私有的,通杀!!)
//oc特有的kvc(key-value-coding)键值编码
//通过kvc对属性赋值 value 为属性的值,key为属性的名称
//kvc为oc动态运行时机制的一个特性,(先找有没有setName方法,没有 就找name变量,再没有,找_name)
[_stu setValue:@"林俊杰" forKey:@“name"];
//根据属性名称,获取属性的值
NSLog(@"name=%@“,[_stu valueForKey:@“name"]);
//任何NSObject(或子类)对象 都可以使用kvc
//需要注意的是key必须是存在的,如果不存在程序就挂了
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKey:(NSString *)key;
【KVO】
//kvo (key-value-observer)(键-值-观察) (对符合kvc操作的变量的观察)
//让self成为_user中name属性的观察者,一旦有对name赋值的操作,self都能监测到,从而self可以进行后续的处理
//addObserver:指定观察者 ;keyPath:要观察的属性
//options NSKeyValueObservingOptionNew/NSKeyValueObservingOptionOld 对属性新旧值的观察
[_user addObserver:self forKeyPath:@“name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
//self监测到name的赋值操作后,会触发此方法
//keyPath 观察的成员变量名(本例中为name)
//object 为被观察的对象 (_user)
//change 带有变量变化前后的值
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([object isKindOfClass:[User class]]) {
//取到name属性的旧值
NSString *old = [change objectForKey:@"old"];
//获取name的新值
NSString *new = [change objectForKey:@"new"];
NSLog(@“%@====%@“,old,new);
}
}
//取消观察者
[_user removeObserver:self forKeyPath:@“name"];
//添加和取消观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
响应事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
【本地视频播放】
//导入系统框架 MediaPlayer.framework
#import <MediaPlayer/MediaPlayer.h>
NSString *videoPath = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"mp4"];
//本地视频
NSURL *url = [NSURL fileURLWithPath:videoPath];
//初始化带有视频播放器的控制器
_playController =[[MPMoviePlayerViewController alloc] initWithContentURL:url];
//弹出视频播放器的界面
[self presentViewController:_playController animated:YES completion:nil];
//下面三个方法可不写
//moviePlayer属性,为视频播放器,操作和音频类似,有准备,放,暂停等
//指定播放的视频资源的类型,MPMovieSourceTypeFile(普通的文件类的视频资源)
_playController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
//预备
[_playController.moviePlayer prepareToPlay];
//放
[_playController.moviePlayer play];
//监听播放完成事件(播放完成时会自动发送name:MPMoviePlayerPlaybackDidFinishNotification这个通知)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playBack) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
- (void)playBack{
//从通知中心,移除自身的观察者身份
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
if (_playController) {
//停止播放
[_playController.moviePlayer stop];
_playController = nil;
}
}
//滚动字幕,跑马灯
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(20, 100, 150, 25)];
bgView.clipsToBounds = YES;
bgView.backgroundColor = [UIColor grayColor];
[self.view addSubview:bgView];
UILabel *runLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 150, 25)];
runLabel.text = @"这句话只是为了展示一下跑马灯的效果";
runLabel.textColor = [UIColor whiteColor];
[bgView addSubview:runLabel];
[runLabel sizeToFit];
CGRect frame = runLabel.frame;
frame.origin.x = bgView.frame.size.width;
runLabel.frame = frame;
[UIView beginAnimations:nil context:NULL];
//动画时间(参数需要按需调整)
[UIView setAnimationDuration:frame.size.width/20.0f];
//重复次数
[UIView setAnimationRepeatCount:CGFLOAT_MAX];
//匀速
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
//返回效果
[UIView setAnimationRepeatAutoreverses:NO];
frame.origin.x = -frame.size.width;
runLabel.frame = frame;
[UIView commitAnimations];
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController ()
{
MPMoviePlayerViewController *_mpvc;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)btnClick:(UIButton *)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"mp4"];
//本地文件路径
NSURL *url = [NSURL fileURLWithPath:path];
//网络文件地址
url = [NSURL URLWithString:@"http://love.local/iOS/1.mp4"];
//创建一个自带视频播放器的vc
_mpvc = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
//弹出播放视频的vc
[self presentMoviePlayerViewControllerAnimated:_mpvc];
//通知中心添加一个观察者self
//self开始监听播放完成的广播,收到广播以后就调playingBack
//当视频播放完成或者用户点击了done,系统都会发送这个广播
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playingBack) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}
- (void)playingBack
{
//移除观察者
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
//播放完成以后,将播放器的内存释放
_mpvc = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
----------------------------------------------------------分割----------------------------------------------------------
#import <Foundation/Foundation.h>
@interface Dog : NSObject
{
NSString *_name;
}
@property (nonatomic, copy) NSString *job;
@end
#import "Dog.h"
@interface Dog ()
{
NSString *_long;
}
@end
@implementation Dog
{
//实现部分也能声明全局的变量,只不过一般不这样干
NSString *_height;
}
//使用kvc设置变量的时候,如果key不存在,会调用到这个方法里
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
NSLog(@"===%@",key);
}
//使用kvc查询变量的时候,如果key不存在,会调用到这个方法里
- (id)valueForUndefinedKey:(NSString *)key
{
NSLog(@"get === %@",key);
return nil;
}
@end
#import "ViewController.h"
#import "Dog.h"
@interface ViewController ()
{
Dog *bai;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
bai = [[Dog alloc] init];
bai.job = @"qqq";
NSLog(@"job = %@",bai.job);
//key-value-coding kvc
//键-值-编码
//功能就是访问成员变量(公有,私有通杀)
//1,会先找setName:这个方法,有就调用
//2,如果没有setter方法,就找_name这个变量
//3,如果找不到_name,就找name
//如果key不存在有2种情况
//a,对象没实现容错方法,就会崩
//b,对象实现了容错方法,会直接调用
[bai setValue:@"www" forKey:@"age"];
NSLog(@"2 = %@",[bai valueForKey:@"age"]);
/**********开始kvo********/
//给bai指向的对象添加一个观察者,self
//self开始观察bai里面name(_name)这个变量,只要这个变量发生了改变,就会调用到观察者事件里
[bai addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}
//观察者事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keyPath = %@, class = %@",keyPath,[object class]);
NSLog(@"dic = %@",change);
}
- (IBAction)btnClick:(UIButton *)sender
{
[bai setValue:[NSString stringWithFormat:@"%d==",arc4random_uniform(20)] forKey:@"name"];
}
- (void)dealloc
{
//取消观察
[bai removeObserver:self forKeyPath:@"name"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end