极客班 iOS 设计模式(二)

重点在通知模式流程图,大致了解几种通知模式的用途的区别。都是理论的东西,还是希望实际写代码时联系理论,仔细考虑选择。

课件下载:https://github.com/gewill/GeekBand-iOS-Demo/tree/master/Design%20Patterns

6. 委托模式

  • 复杂的模型,scrollView,tableView,collectionView
  • 单⼀一个类无法表现复杂的设计
  • 设计拆分
  • 方便重⽤
  • delegate 独立对象
  • 清晰定义功能,变化行为/自定义界⾯面
  • 松散耦合,容易扩展

以 Master-Detail Application 模板详细介绍了委托模式。孔老师喜欢直接看类的定义。

UITableView delegation
Jump to Definition
UITableViewDataSource

7. 观察者和消息通知

MVC
Observer pattern

  • 定义对象间一种⼀对多的依赖关系,使得每当一个对象改变状态,则所有依赖于他的对象都会得到通知并被自动更新。
  • Subject被观察者:定义被观察者必须实现的职责,它必须能够动态的增加、取消 观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责
    :管理观察者并通知观察者
  • Observer观察者:观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。
  • 具体的被观察者:定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
  • 具体的观察者:每个观察者在接收到消息后的处理反应是不同的,各个观察者有自己的处理逻辑。

通知

Notification pattern

应用场景:

  • 窗口变化通知
  • 系统键盘的出现和消失/位置⼤小变化
  • UITextField 字符变化通知(可以用来限制输入长度)
  • MPMoviePlayerController 播放器的⾏为变化(开始结束等事件)
  • 自定义Class使用

代码实现参看李久寧的文章:iOS 设计模式之四:观察者模式

Key-Value-Coding and Key-Value-Observing

可在 Xcode 中 Open Quickly(⇧⌘O),查看NSKeyValueCoding.h协议的内容。

典型的例子 NSOperation and NSOperationQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/* NSOperation.h
Copyright (c) 2006-2014, Apple Inc. All rights reserved.
*/

@interface NSOperation : NSObject {
@private
id _private;
int32_t _private1;
#if __LP64__
int32_t _private1b;
#endif
}

- (void)start;
- (void)main;

@property (readonly, getter=isCancelled) BOOL cancelled;
- (void)cancel;

@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0);
@property (readonly, getter=isReady) BOOL ready;

NSOperationQueue

###延伸阅读:

  • Apple Key-Value Coding Programming Guide

    This document describes the NSKeyValueCoding informal protocol, which defines a mechanism allowing applications to access the properties of an object indirectly by name (or key), rather than directly through invocation of an accessor method or as instance variables.

    Dot Syntax and Key-Value Coding: Objective-C’s dot syntax and key-value coding are orthogonal technologies. You can use key-value coding whether or not you use the dot syntax, and you can use the dot syntax whether or not you use KVC. Both, though, make use of a “dot syntax.” In the case of key-value coding, the syntax is used to delimit elements in a key path. Remember that when you access a property using the dot syntax, you invoke the receiver’s standard accessor methods.

  • KVC 和 KVO
  • 消息传递机制

    我们会常常提及“接收者”和“发送者”。它们在消息传递中的意思可以通过以下的例子解释:一个 table view 是发送者,它的 delegate 就是接收者。Core Data managed object context 是它所发出的 notification 的发送者,获取 notification 的就是接收者。一个滑块 (slider) 是 action 消息的发送者,而实现这个 action (方法)的是它的接收者。任何修改一个支持 KVO 的对象的对象是发送者,这个 KVO 对象的观察者就是接收者。明白精髓了吗?
    基于不同消息传递机制的特点的流程图
    communication-patterns-flow-chart

9. 归档和解档

###NSCoding

是一个简单的协议,有两个方法: -initWithCoder: 和 encodeWithCoder:。遵循NSCoding协议的类可以被序列化和反序列化,这样可以归档到磁盘上或分发到网络上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@interface Book : NSObject <NSCoding>
@property NSString *title;
@property NSString *author;
@property NSUInteger pageCount;
@property NSSet *categories;
@property (getter = isAvailable) BOOL available;
@end

@implementation Book

#pragma mark - NSCoding

- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}

self.title = [decoder decodeObjectForKey:@"title"];
self.author = [decoder decodeObjectForKey:@"author"];
self.pageCount = [decoder decodeIntegerForKey:@"pageCount"];
self.categories = [decoder decodeObjectForKey:@"categories"];
self.available = [decoder decodeBoolForKey:@"available"];

return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.title forKey:@"title"];
[encoder encodeObject:self.author forKey:@"author"];
[encoder encodeInteger:self.pageCount forKey:@"pageCount"];
[encoder encodeObject:self.categories forKey:@"categories"];
[encoder encodeBool:[self isAvailable] forKey:@"available"];
}

@end

NSKeyedArchiver 和 NSKeyedUnarchiver

提供了很方便的API把对象读取/写入磁盘。一个基于NSCoding的table view controller可以通过file manager设置它的属性集合。

1
2
3
[NSKeyedArchiver archiveRootObject:books toFile:@"/path/to/archive"];

[NSKeyedUnarchiver unarchiveObjectWithFile:@"/path/to/archive"];

NSUserDefaults

每个应用程序都有自己的user preferences,它可以存储和检索遵循NSCoding协议的对象或者是C类型数据。

1
2
3
4
5
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:books];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"books"];

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"books"];
NSArray *books = [NSKeyedUnarchiver unarchiveObjectWithData:data];

###延伸阅读:

10. 复制模式

  • 创建一个对象的新副本
  • 复制一个复杂对象时,保护一个一样的对象,还是包含原来对象的副本
  • 用户界面上的复制/粘贴 有些对象封装了独一无⼆的资源,复制没有意义
  • 浅复制和深复制。顾名思义,浅复制,并不拷⻉对象本⾝,仅仅是拷贝指向对象的指针;深复制是直接拷贝整个对象内存到另⼀块内存中

- initWithDictionary:copyItems 就是个典型例子,可深可浅。

参看 MicroCai 的文章:iOS 集合的深复制与浅复制