iOS笔试面试iOS面试题移动开发

可能碰到的iOS笔试面试题(20)--设计模式

2016-05-04  本文已影响2098人  b485c88ab697

设计模式

从设计模式的角度分析Delegate、Notification、KVO的区别

三者优缺点:

delegate的优势:

1.非常严格的语法。所有将听到的事件必须是在delegate协议中有清晰的定义。

2.如果delegate中的一个方法没有实现那么就会出现编译警告/错误

3.协议必须在controller的作用域范围内定义

4.在一个应用中的控制流程是可跟踪的并且是可识别的;

5.在一个控制器中可以定义定义多个不同的协议,每个协议有不同的delegates

6.没有第三方对象要求保持/监视通信过程。

7.能够接收调用的协议方法的返回值。这意味着delegate能够提供反馈信息给controller

8.经常被用在存在父子关系的对象之间通信,例如控制器和控制器的view(自己加的理解)

缺点:

1.需要定义很多代码:1.协议定义;2.controller的delegate属性;3.在delegate本身中实现delegate方法定义

2.在释放代理对象时,需要小心的将delegate改为nil。一旦设定失败,那么调用释放对象的方法将会出现内存crash

3.在一个controller中有多个delegate对象,并且delegate是遵守同一个协议,但还是很难告诉多个对象同一个事件,不过有可能。

4.经常用在一对一的通信。(不知道是缺点还是优点,只能算是特点)(自己加的理解)

notification的优势:

1.不需要编写多少代码,实现比较简单

2.对于一个发出的通知,多个对象能够做出反应,即一对多的方式实现简单

3.controller能够传递context对象(dictionary),context对象携带了关于发送通知的自定义的信息

缺点:

1.在编译期不会检查通知是否能够被观察者正确的处理;

2.在释放注册的对象时,需要在通知中心取消注册;

3.在调试的时候应用的工作以及控制过程难跟踪;

4.需要第三方对象来管理controller与观察者对象之间的联系;

5.controller和观察者需要提前知道通知名称、UserInfo dictionary keys。如果这些没有在工作区间定义,那么会出现不同步的情况;

6.通知发出后,controller不能从观察者获得任何的反馈信息(相比较delegate)。

KVO的优势:

1.能够提供一种简单的方法实现两个对象间的同步。例如:model和view之间同步;

2.能够对非我们创建的对象,即内部对象的状态改变作出响应,而且不需要改变内部对象(SKD对象)的实现;

3.能够提供观察的属性的最新值以及先前值;

4.用key paths来观察属性,因此也可以观察嵌套对象;

5.完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察

6.可以一对多。

缺点:

1.我们观察的属性必须使用strings来定义。因此在编译器不会出现警告以及检查;

2.对属性重构将导致我们的观察代码不再可用;

3.复杂的“IF”语句要求对象正在观察多个值。这是因为所有的观察代码通过一个方法来指向;

4.当释放观察者时不需要移除观察者。

  1. 效率 肯定是delegate比NSNotification高。

delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值,

也就是delegate方法的结果。比如-windowShouldClose:,需要关心返回的是yes还是no。所以delegate方法往往包含

should这个很传神的词。也就是好比你做我的delegate,我会问你我想关闭窗口你愿意吗?你需要给我一个答案,我根据你的答案来决定如何做下一

步。相反的,notification最大的特色就是不关心接受者的态度,

我只管把通告放出来,你接受不接受就是你的事情,同时我也不关心结果。所以notification往往用did这个词汇,比如

NSWindowDidResizeNotification,那么NSWindow对象放出这个notification后就什么都不管了也不会等待接

受者的反应。

2、KVO和NSNotification的区别 :

和delegate一样,KVO和NSNotification的作用也是类与类之间的通信,与delegate不同的是1)这两个都是负责发出通知,剩下的事情就不管了,所以没有返回值;2)delegate只是一对一,而这两个可以一对多。这两者也有各自的特点。

总结:

从上面的分析中可以看出3中设计模式都有各自的优点和缺点。在这三种模式中,我认为KVO有最清晰的使用案例,而且针对某个需求有清晰的实用性。而另外两种模式有比较相似的用处,并且经常用来给controller间进行通信。那么我们在什么情况使用其中之一呢?

根据我开发iOS应用的经历,我发现有些过分的使用通知模式。我个人不是很喜欢使用通知中心。我发现用通知中心很难把握应用的执行流程。Userlnfo dictionaries的keys到处传递导致失去了同步,而且在公共空间需要定义太多的常量。对于一个工作于现有的项目的开发者来说,如果过分的使用通知中心,那么很难理解应用的流程。

我觉得使用命名规则好的协议和协议方法定义对于清晰的理解controllers间的通信是很容易的。努力的定义这些协议方法将增强代码的可读性,以及更好的跟踪你的app。代理协议发生改变以及实现都可通过编译器检查出来,如果没有将会在开发的过程中至少会出现crash,而不仅仅是让一些事情异常工作。甚至在同一事件通知多控制器的场景中,只要你的应用在controller层次有着良好的结构,消息将在该层次上传递。该层次能够向后传递直至让所有需要知道事件的controllers都知道。当然会有delegation模式不适合的例外情况出现,而且notification可能更加有效。例如:应用中所有的controller需要知道一个事件。然而这些类型的场景很少出现。另外一个例子是当你建立了一个架构而且需要通知该事件给正在运行中应用。

根据经验,如果是属性层的事件,不管是在不需要编程的对象还是在紧紧绑定一个view对象的model对象,我只使用观察。对于其他的事件,我都会使用delegate模式。如果因为某种原因我不能使用delegate,首先我将估计我的app架构是否出现了严重的错误。如果没有错误,然后才使用notification。

什么是设计模式

设计模式的分类

类工厂方法是什么?

单例是什么?

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

  1. 单例模式的要点:

显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

  1. 单例模式的优点:

    • 实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例。
    • 灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

手写一下单例方法(或者单例模式的设计:GCD 方式和同步锁方式的区别在哪里?unlock 呢?GCD 是怎么保证单例的?)

imageimage

简要描述观察者模式,并运用此模式编写一段代码?

谈谈你对MVC的理解?为什么要用MVC?在Cocoa中MVC是怎么实现的?你还熟悉其他的OC设计模式或别的设计模式吗?

MVC优点不正确的是

A 低耦合性
B 高重用性和可适用性
C 较低的生命周期成本
D 代码高效率

如何理解MVVM框架,它的优点和缺点在哪?运用此框架编写一段代码,建议采用ReactiveCocoa库实现;

优点:
层次更加分明清晰
代码简洁优雅
减少VC的复杂性
代码和界面完全分离
方便测试

缺点:
MVVM需要使用数据绑定机制,对于OS X 开发,可以直接使用Coocoa Binding,对于iOS,没有太好的数据绑定方法,可以使用KVO,但如果需要绑定的属性太多的话,需要编写大量的selector代码。

ReactiveCocoa提供了一种很方便优雅的绑定机制。

ReactiveCocoa

哪些途径可以让 ViewController 瘦下来?

你在你的项目中用到了哪些设计模式?

项目中使用了很多的设计模式,我相信面试官最好听到的不仅仅是设计模式的名字,更想听到的是这些设计模式在项目中如何应用。因此,笔者认为这个问题隐式地说明了应该回答设计模式及其在项目中的应用。
参考答案:
•   单例设计模式:在项目中,单例是必不可少的。比如UIApplication、NSUserDefaults就是苹果提供的单例。在项目中经常会将用户数据管理封装成一个单例类,因此用户的信息需要全局使用。
•   MVC设计模式:现在绝大部分项目都是基于MVC设计模式的,现在有一部分开发者采用MVVM、MVP等模式。
•   通知(NSNotification)模式:通知在开发中是必不可少的,对于跨模块的类交互,需要使用通知;对于多对多的关系,使用通知更好实现。
•   工厂设计模式:在我的项目中使用了大量的工厂设计模式,特别是生成控件的API,都已经封装成一套,全部是扩展的类方法,可简化很多的代码。
•   KVC/KVO设计模式:有的时候需要监听某个类的属性值的变化而做出相应的改变,这时候会使用KVC/KVO设计模式。在项目中,我需要监听model中的某个属性值的变化,当变化时,需要更新UI显示,这时候使用KVC/KVO设计模式就很方便了。
就说这么多吧,还有很多的设计模式,不过其它并不是那么常用。

如何实现单例,单例会有什么弊端?

单例在项目中的是必不可少的,它可以使我们全局都可共享我们的数据。这只是简单的问题,大家根据自己的情况回答。
参考答案:
•   首先,单例写法有好几种,通常的写法是基于线程安全的写法,结合dispatch_once来使用,保证单例对象只会被创建一次。如果不小心销毁了单例,再调用单例生成方法是不会再创建的。
•   其次,由于单例是约定俗成的,因此在实际开发中通常不会去重写内存管理方法。
单例确实给我们带来的便利,但是它也会有代价的。单例一旦创建,整个App使用过程都不会释放,这会占用内存,因此不可滥用单例。

你在你的项目中用到了哪些设计模式?

单例书写

1、 获取单例对象的方法

+ (DataHandle *)sharedDataHandle; // 创建单例对象的方法。类方法 命名规则: shared + 类名
2、 方法的实现

// 因为实例是全局的 因此要定义为全局变量,且需要存储在静态区,不释放。不能存储在栈区。
static DataHandle *handle = nil;

// 伪单例 和 完整的单例。 以及线程的安全。
// 一般使用伪单例就足够了 每次都用 sharedDataHandle 创建对象。
+ (DataHandle *)sharedDataHandle
{
    // 添加同步锁,一次只能一个线程访问。如果有多个线程访问,等待。一个访问结束后下一个。
    @synchronized(self){
        if (nil == handle) {
            handle = [[DataHadle alloc] init];             
        }
    }
  return handle;
}


完整的单例
完整的单例要求比较高,不仅要求我们通过方法获取的对象是单例,如果有 对该对象进行copy mutableCopy copyWithZone 等操作时,也是同一份对象。这就要求我们必须重写这些方法,在这些方法内部做一些操作。

完整的单例要做到四个方面:

为单例对象实现一个静态实例,然后设置成nil,
构造方法检查静态实例是否为nil,是则新建并返回一个实例,
重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实例的时候不会产生一个新实例,
适当实现copyWithZone,,retain,retainCount,release和autorelease 等方法

1、 获取单例对象的方法

+ (DataHandle *)sharedDataHandle; // 创建单例对象的方法。类方法 命名规则: shared + 类名
2、 方法的实现
@synchronized(self){
        if (nil == handle) {
            handle = [[super allocWithZone:nil] init]; // 避免死循环
            // 如果 在单例类里面重写了 allocWithZone 方法 ,在创建单例对象时 使用 [[DataHandle alloc] init] 创建,会死循环。

        }
    }
 return handle;

3、 重写 allocWithZone copy mutableCopy copyWithZone

防止外界拷贝造成多个实例, 保证实例的唯一性。
注意:如果自己重写了 allocWithZone 就不要再调用自身的 alloc 方法,否则会出现死循环。

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [DataHandle sharedDataHandle];
}

- (id)copy
{
    return self;
}

- (id)mutableCopy
{
    return self;
}

+ (id)copyWithZone:(struct _NSZone *)zone
{
    return self;
}
4、 重写 alloc retain release autorelease retainCount

+ (instancetype)alloc
{
    return [DataHandle sharedDataHandle];
}

//  因为只有一个实例, 一直不释放,所以不增加引用计数。无意义。
- (instancetype)retain
{
    return self;
}

- (oneway void)release
{
    // nothing
}

- (instancetype)autorelease
{
    return self;
}

- (NSUInteger)retainCount
{
    return NSUIntegerMax; // 返回整形最大值。
}

文章如有问题,请留言,我将及时更正。

满地打滚卖萌求赞,如果本文帮助到你,轻点下方的红心,给作者君增加更新的动力。

上一篇 下一篇

猜你喜欢

热点阅读