Controller直接通信,主要从以下5个方面来探究KV

图片 1标题图片

MVC:

Model: 负责存储,定义,操作数据;
View: 用来展示给用户数据,和用户进行交互操作的;
Controller:是 View 和 Model 的协调者,其可以直接与 Model 和 View 通信;而 View 不能和 Controller直接通信,需要利用代理协议的方式才能间接进行通信;或者通过 target-action 的方式进行通信, target 会留出 outlet 接口供 Controller 调用;同样 Model 和 Controller 也不能进行直接的通信,可以通过通知中心和 KVO 的方式来实现二者之间的通行; Model和 View 是不能直接进行通信的,只能通过 Controller 进行传递;

IOS SDK详解之KVO

 

 前言:KVC和KVO是帮助我们驾驭objective C动态特性工具。KVO是建立在KVC基础上的,所以不了解KVC的同学可以参见我的这篇博客。这里我不会再重复讲解KVC。
 
本文的内容

KVO的定义
KVO的典型使用场景。
手动KVO
几点KVO要说的地方


KVC和KVO的基础使用方法

首先,KVC(Key Value Coding)就是由NSKeyValueCoding协议提供,而NSObject方法中也实现了这个方法,所以说KVC可以在任何页面调用。

那么KVO(Key Value Observer)呢,就是监制监听,说白了就是看着Model中的哪一个值改变了,然后执行监听方法。

所以我对KVC的理解就是动态的为Model赋值和取值,KVO就是看着KVC,如果使用KVC改变了Model的值,那么就调用监听方法。

好了不多说了,直接上代码,实现原理后续继续写。

首先创建一个Person类,类中有一个name属性,personMessage是它下一层的Model

-(void)setValue:(id)value forUndefinedKey:(NSString *)key;

这个方法的作用是当取值时,没有找到你写的key值得时候,调用此方法

作用就是防止key值写错导致程序崩溃

图片 2

erson.h

Person.m中实现一下

图片 3

Person.m

创建PersonMessage类,类中有两个属性,sex、age

图片 4

PersonMessage.h

同理在PersonMessage.m中

图片 5

PersonMessage.m

然后在ViewController中使用KVC和KVO

使用KVC进行赋值的三种方式

图片 6

ViewController.m

使用KVC进行取值的三种方式

图片 7

ViewController.m

打印信息如下

图片 8

以上是KVC的取值和赋值,接下来简述KVO监听的方法

首先创建一个监听者

图片 9

person:调用的model

addObserver:观察者  self(用本类调用)

forKeyPath:要监听的属性名

options:观察属性的新值,旧值等的一些配置(枚举值)

context:上下文 可以为KVO的回调方法传值

options的枚举值有四个

NSKeyValueObservingOptionOld 把更改之前的值提供给处理方法

NSKeyValueObservingOptionNew 把更改之后的值提供给处理方法

NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。

NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。

实现回调方法(当被监听的对象的值发生变化时回调此方法)

图片 10

监听者移除之后就完成此次监听

以上就是KVO的基本用法

注意:

使用步骤:

1、注册观察者(为被观察这指定观察者以及被观察者属性)

2、实现回调方法

3、触发回调方法

4、移除观察者

一般KVO的崩溃原因如下

1、被观察的对象销毁掉了(被观察的对象是一个局部变量)

2、观察者被释放掉了,但是没有移除监听(如模态推出,push,pop等)

3、注册的监听没有移除掉,又重新注册了一遍监听

谢谢大家的支持,有什么问题请在下面留言。

图片 11KVO原理探究.jpeg

IOS的KVO是一种非常便捷的回调方式,但不知怎么很多初级、中级开发者很少用到它。我回顾了自己的项目,发现很多频繁调用的函数可以用KVO的方式更加优雅得解决,但由于平时不怎么用,略微有点手生,所以借此机会补补课。

缺点:

  • 增加系统和实现的复杂性,意味着将要管理更多的文件;
  • 视图和控制器之间的联系过于紧密,耦合性太强;
  • MVC 不适合小型甚至中等规模的应用程序;
  • 视图和数据模型的低效率访问;

一 KVO的定义

KVO提供了一种key-value-observing的机制,也就是说可以通过监听key,来获得value的变化。用来在对象之间监听状态变化。使用KVO的类要遵循 协议,事实上,任何继承自NSObject的类,都遵循了这个协议。而Object C中,几乎所有的类都源自NSObject

使用KVO通常分为三步

KVO全称Key Value Observing,直译为键值观察。KVO 作为 iOS 中一种强大并且有效的机制,为 iOS 开发者们提供了很多的便利;可以使用 KVO 来检测对象属性的变化、快速做出响应,这能够为开发者在开发强交互、响应式应用以及实现视图和模型的双向绑定时提供大量的帮助。

我们先来看看官方对KVO的解释:

优点:

  • 低耦合性;
  • 可移植性好,可维护性强;
  • 利于管理,较低的声明周期成本;

1.1 订阅想要监听的keypath

用函数

- (void)addObserver:(NSObject *)anObserver
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
            context:(void *)context

注册通知

observer:观察者,也就是KVO通知的订阅者。订阅着必须实现
observeValueForKeyPath:ofObject:change:context:方法 keyPath:描述将要观察的属性,相对于被观察者。 options:KVO的一些属性配置;有四个选项。 context: 上下文,这个会传递到订阅着的函数中,用来区分消息,所以应当是不同的。

options所包括的内容

NSKeyValueObservingOptionNew:change字典包括改变后的值 NSKeyValueObservingOptionOld:change字典包括改变前的值 NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知 NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)


Demo源码见KVODemo,主要从以下5个方面来探究KVO:

Automatic key-value observing is implemented using a technique called isa-swizzling... When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class ..

MVVM:

图片 12

MVVM 和 MVC 的对比

在MVC模式的iOS开发中,Controller承担了太多的代码,包含着我们的视图处理逻辑和业务逻辑;使 Controller 显得很臃肿, MVVM 就应运而生;
在MVVM中,我们将视图处理逻辑从C中剥离出来给V,剩下的业务逻辑部分被称做View-Model;

Model:数据层。

ViewModel层,就是View和Model层的粘合剂,他是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。说白了,就是把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。

View层,就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。

图片 13

MVVM 结构.png

1.2 响应状态变化

每当监听的keyPath发生变化了,就会在这个函数中回调。

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context

keyPath:被监听的keyPath , 用来区分不同的KVO监听。 object: 被观察修改后的对象(可以通过object获得修改后的值) change:保存信息改变的字典(可能有旧的值,新的值等) context:上下文,用来区分不同的KVO监听。


  1. KVO基本使用
  2. KVO触发模式
  3. KVO属性依赖
  4. KVO基本原理
  5. KVO容器观察

好吧,说的不大清楚。。这里我们不讨论isa指针,具体的可以网上查下资料。后面的话简单的说就是说有个一个类classA监听ClassB,当classB的某个属性值改变,classA就能得到反馈。总的来说很像IOS的消息通知机制,注册一个通知,然后监听。

优点:

  • MVVM 可以兼容你当下使用的 MVC 架构。
  • MVVM 增加你的应用的可测试性。
  • MVVM 配合一个绑定机制效果最好。
    如我们之前所见,MVVM 基本上就是 MVC 的改进版,所以很容易就能看到它如何被整合到现有使用典型 MVC 架构的应用中;

当Model 是不可变的,我们可以只在初始化的时候指定我们 View Model 的属性。对于可变 Model,我们还需要使用一些绑定机制,这样 View Model 就能在背后的 Model 改变时更新自身的属性。此外,一旦 View Model 上的 Model 发生改变,那 View 的属性也需要更新。Model 的改变应该级联向下通过 View Model 进入 View。
在 OS X 上,我们可以使用 Cocoa 绑定,但在 iOS 上我们并没有这样好的配置可用。我们想到了 KVO(Key-Value Observation),而且它确实做了很伟大的工作。然而,对于一个简单的绑定都需要很大的样板代码,更不用说有许多属性需要绑定了。作为替代,我个人喜欢使用 ReactiveCocoa,但 MVVM 并未强制我们使用ReactiveCocoa。MVVM 是一个伟大的典范,它自身独立,只是在有一个良好的绑定框架时做得更好。

那 MVVM 相比 MVC 到底有哪些好处呢?主要可以归纳为以下三点:
1.由于展示逻辑被抽取到了 viewModel 中,所以 view 中的代码将会变得非常轻量级;
2.由于 viewModel 中的代码是与 UI 无关的,所以它具有良好的可测试性;
3.对于一个封装了大量业务逻辑的 model 来说,改变它可能会比较困难,并且存在一定的风险。在这种场景下,viewModel 可以作为 model 的适配器使用,从而避免对 model 进行较大的改动。

1.3 在适当的时候,取消订阅

通常使用两个函数

- (void)removeObserver:(NSObject *)anObserver
            forKeyPath:(NSString *)keyPath
- (void)removeObserver:(NSObject *)observer
            forKeyPath:(NSString *)keyPath
               context:(void *)context

一般在remove的时候会这么写,因为remove的时候,无法判读啊remove是否成功了

    @try {
        [object removeObserver:self forKeyPath:keyPath];
    }
    @catch (NSException *exception) {
        NSLog(@%@,exception);
    }

1.1 使用KVO分为三个步骤:

  1. 通过addObserver:forKeyPath:options:context:方法注册观察者,观察者可以接收keyPath属性的变化事件。
  2. 在观察者中实现observeValueForKeyPath:ofObject:change:context:方法,当keyPath属性发生改变后,KVO会回调这个方法来通知观察者。
  3. 当观察者不需要监听时,可以调用removeObserver:forKeyPath:方法将KVO移除。 需注意调用removeObserver需要在观察者消失之前,否则会导致Crash。

一个购物车的样子和要素大概和下面这张图类似:

观察者模式(通知中心,KVO)

二 KVO的典型使用场景 - model 与 view的同步

这里,你将看到一个完整的KVO的例子。和上篇KVC一样,我写了个类似的demo。点击random会随机改变User的age,然后UI上要进行同步显示出新的和旧的age。
图片 14

实现过程如下:
定义了一个User类来作为Model

@interface User : NSObject
@property (strong,nonatomic) NSString * name;
@property (nonatomic) NSUInteger age;
@end

定义两个静态的变量,一个作为keyPath,一个作为context

static  NSString * observename = @age;
static void * privateContext = 0;

然后在viewWillAppear中注册(订阅)KVO,在viewWillDisappear中删除KVO

-(void)viewWillAppear:(BOOL)animated{
    [self.user addObserver:self
                forKeyPath:observename
                   options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:privateContext];
}
-(void)viewWillDisappear:(BOOL)animated{
    @try {
        [self.user removeObserver:self forKeyPath:observename];
    }
    @catch (NSException *exception) {
        NSLog(@%@,exception);
    }
}

当点击random的时候,age会改变

- (IBAction)random:(id)sender {
    self.user.age = arc4random()%100 +1;
}

然后,在上面提到的函数中进行model和view的同步

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if (context == privateContext) {
        if ([keyPath isEqualToString:observename]) {
            NSNumber * old = [change objectForKey:NSKeyValueChangeOldKey];
            NSNumber * new = [change objectForKey:NSKeyValueChangeNewKey];
            self.lastvalue.text = [NSString stringWithFormat:@%@,old];
            self.newvalue.text = [NSString stringWithFormat:@%@,new];
        }
    }
}

1.2 addObserver方法

在注册观察者时,可以传入下列参数:

  • Observer参数,观察者对象。

  • keyPath参数,需要观察的属性。由于是字符串形式,传错容易导致Crash。一般利用系统的反射机制NSStringFromSelector(@selector。

  • options参数,参数是一个枚举类型。

    NSKeyValueObservingOptionNew 接收新值,默认为只接收新值NSKeyValueObservingOptionOld 接收旧值NSKeyValueObservingOptionInitial 在注册时立即接收一次回调,在改变时也会发送通知NSKeyValueObservingOptionPrior 改变之 前发一一次,改变之后发-一次

  • Context参数,传入任意类型的对象,在接收消息回调的代码中可以接收到这个对象,是KVO中的一种传值方式。注意:调用addObserver方法后,KVO并不会对观察者进行强引用,所以需要注意观察者的生命周期,否则会导致观察者被释放带来的Crash。

本文由必威发布于必威-编程,转载请注明出处:Controller直接通信,主要从以下5个方面来探究KV

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。