iOS 设计模式
很赞的总结
中文版
https://github.com/mobilefeng/BlueLibrary
==========MVC(model, view, controller)模式==========
1. model
Album:专辑数据
Album+TableRepresentation:扩展专辑数据,专门给UITableView展示用⭐️
2. view
AlbumView:专辑图片
HorizontalScroller:自定义的横滚视图 ⭐️
3. controller
ViewController
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, HorizontalScrollerDelegate> {
// Model
NSArray *allAlbums;
NSDictionary *currentAlbumData;
NSInteger currentAlbumIndex;
// View
HorizontalScroller *scroller;
UITableView *dataTable;
}
- C管理着M和V,在C中有5个属性
= 在viewdidload中将两个view添加到C的self.view中
- C声明实现三个协议
= 将V的委托属性设置为C
= 在C中实现了协议中声明的方法
==========单例(Singleton)模式==========
官方定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
// LibraryAPI.h
+ (instancetype)sharedInstance; // LibraryAPI.m
+ (instancetype)sharedInstance {
static id _sharedInstance = nil;
static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{
_sharedInstance = [[LibraryAPI alloc] init];
}); return _sharedInstance;
} // ViewController
allAlbums = [[LibraryAPI sharedInstance] getAlbums];
1. 在.h中声明一个类方法,返回一个实例
2. 声明一个静态变量 _sharedInstance 保存类的实例
3. 声明一个静态变量 dispatch_once_t ,它确保初始化器代码只执行一次
4. 使用 GCD 执行初始化LibraryAPI变量的block,这正是单例模式的关键:一旦类已经被初始化,初始化器永远不会再被调用。
5. 调用时直接使用类方法
==========外观(Facade)模式==========
官方定义:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一系统更加容易使用
(比如把用户中心、商品中心、交易中心、检索、营销、客服统一起来,提供BNAPI接口,供APP调用,这就是活生生的外观模式)
外观模式,是将一些复杂的类封装起来提供单一接口
用 PersistencyManager 本地保存专辑数据,用 HTTPClient 处理远程连接
用 LibraryAPI 保存 PersistencyManager 和 HTTPClient 的实例,然后 LibraryAPI 将暴露一个简单的API去访问这些服务
@interface LibraryAPI (){
PersistencyManager *persistencyManager;
HTTPClient *httpClient;
BOOL isOnline;
}
==========装饰器(Decorator)模式==========
官方定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
在不修改原来代码的情况下动态的给对象增加新的行为和职责,它通过一个对象包装被装饰对象的方法来修改类的行为,这种方法可以做为子类化的一种替代方法
Category (类别)
在 Album 类基础上扩展出 Album+TableRepresentation 类
@interface Album (TableRepresentation) // tr is short for TableRepresentation
- (NSDictionary*)tr_tableRepresentation; @end
- 创建的方法
1. Command + N
2. 选择 iOS - Source - Objective-C File
3. File Type 选择 Category,Class 填基于的类名,File填扩展的名
- 特点
可以直接使用 Album的属性
==========适配器(Adapter)模式==========
官方定义:将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
在C++中用多重继承实现,但是OC是没有多重继承的,于是OC中是通过协议来实现
// ViewController.h
@interface ViewController : UIViewController // ViewController.m
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, HorizontalScrollerDelegate> {
// ...
HorizontalScroller *scroller;
UITableView *dataTable;
}
一方面,ViewController 继承了 UIViewController
另一方面,为了能利用类 HorizontalScroller,将其方法封装成协议 HorizontalScrollerDelegate(也就是接口),供 ViewController 使用
Delegation (委托)
创建委托协议
1 @protocol HorizontalScrollerDelegate;
2
3 @interface HorizontalScroller : UIView
4
5 // weak 防止循环引用
6 // id 意味着 delegate 属性可以用任何遵从 HorizontalScrollerDelegate 的类赋值
7 @property (weak) id<HorizontalScrollerDelegate> delegate;
8 - (void)reload;
9
10 @end
11
12 // _____________________________________________________________________________________
13 //
14 @protocol HorizontalScrollerDelegate <NSObject>
15
16 @required
17 - (NSInteger)numberOfViewsForHorizontalScroller:(HorizontalScroller*)scroller;
18
19 - (UIView*)horizontalScroller:(HorizontalScroller*)scroller viewAtIndex:(int)index;
20
21 - (void)horizontalScroller:(HorizontalScroller*)scroller clickedViewAtIndex:(int)index;
22
23 @optional
24 - (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller*)scroller;
25
26 @end
主要分两块:
1. 14-26行是委托协议的声明,这里声明了一个名为 HorizontalScrollerDelegate 的委托协议,包含三个必须实现方法和一个可选实现方法
2. 第7行是给 HorizontalScroller 定义了一个实现 HorizontalScrollerDelegate 的属性 delegate
使用委托协议
1 // 1
2 @interface ViewController () <UITableViewDataSource, UITableViewDelegate, HorizontalScrollerDelegate> {
3 // ...
4 HorizontalScroller *scroller;
5 UITableView *dataTable;
6 }
7
8 // 2
9 - (void)viewDidLoad {
10 [super viewDidLoad];
11
12 // ...
13 scroller.delegate = self;
14 dataTable.delegate = self;
15 // ...
16 }
17
18 // 3
19 // 实现协议中声明的方法
主要分三块:
1. 第2行,在类的interface声明实现XX委托协议,4-5行,通常有实现相应协议对应的属性
2. 13-14行,将熟悉的delegate设置为类本身(self)
3. 19行,实现委托协议中声明的方法
如果一个协议包含的方法太多,可以考虑将其拆分,如:
UITableViewDataSource 和 UITableViewDelegate,前者负责数据源获取,后者负责对数据源进行加工细化
==========观察者(Observer)模式==========
官方定义:又叫发布-订阅(Publish/Subscribe)模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
这是一种松耦合的设计,在MVC中,当需要让模型对象和视图对象在不相互引用的情况下进行通信,就需要观察者模式。
Cocoa中有两种常见的观察者模式:通知(Notification)和KVO(Key-Value Observing)
通知(Notification)
// AlbumView.m
[[NSNotificationCenter defaultCenter] postNotificationName:@"BLDownloadImageNotification" object:self userInfo:@{@"imageView":coverImage, @"coverUrl":albumCover}]; // LibraryAPI.m
- (id)init {
if (self = [super init]) {
// ...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadImage:) name:@"BLDownloadImageNotification" object:nil];
} return self;
} - (void)downloadImage:(NSNotification *)notification {
UIImageView *imageView = notification.userInfo[@"imageView"];
NSString *coverUrl = notification.userInfo[@"coverUrl"];
// ...
} - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
1. 第2行,发送名为BLDownloadImageNotification通知,其中userInfo会作为通知的一部分传递过去(15-16行)
2. 第8行,LibraryAPI 注册为 BLDownloadImageNotification 的观察者,当 AlbumView 发送通知时,系统会通知 LibraryAPI,LibraryAPI 调用 downloadImage: 来下载图片
3. 20-22行,观察者在销毁时,必须退订之前订阅的所有通知,否则一个通知发送给一个已经销毁的对象,会crash
KVO(Key-Value Observing)
它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
// AlbumView.m
// 注册
[coverImage addObserver:self forKeyPath:@"image" options: context:nil];
// 实现回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"image"]) {
[indicator stopAnimating];
}
}
// 移除观察
- (void)dealloc {
[coverImage removeObserver:self forKeyPath:@"image"];
}
1. 注册通知
2. 实现回调方法
3. 移除观察(退订通知)
两点心得:
1. 通知是解决两个类间的消息传递,KVO是解决类内部属性间的消息传递
2. dealloc 中主要就是移除观察(退订通知)
==========观察者(Observer)模式==========
iOS 设计模式的更多相关文章
- IOS设计模式之一(MVC模式,单例模式)
iOS 设计模式-你可能已经听说过这个词,但是你真正理解它意味着什么吗?虽然大多数的开发者可能都会认为设计模式是非常重要的,然而关于设计模式这一主题的文章却不多,并且有时候我们开发者在写代码的时候也不 ...
- iOS 设计模式之工厂模式
iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...
- iOS设计模式之生成器
iOS设计模式之生成器 1.生成器模式的定义 (1): 将一个复杂的对象的构件与它的表示分离,使得相同的构建过程能够创建不同的表示 (2): 生成器模式除了客户之外还包括一个Director(指导者) ...
- IOS设计模式之三:MVC模式
IOS设计模式之三:MVC模式 模型-视图-控制器 这个模式其实应该叫做MCV,用控制器把model与view隔开才对,也就是model与view互相不知道对方的存在,没有任何瓜葛,他们就像一个团 ...
- iOS设计模式 - 享元
iOS设计模式 - 享元 原理图 说明 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分 ...
- iOS设计模式 - 责任链
iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...
- iOS设计模式 - 模板
iOS设计模式 - 模板 原理图 说明 定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 源码 https://github.c ...
- iOS设计模式 - 访问者
iOS设计模式 - 访问者 原理图 说明 表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 1.Visitor 抽象访问者角色,为该对象结构中具 ...
- iOS设计模式 - 迭代器
iOS设计模式 - 迭代器 原理图 说明 提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 源码 https://github.com/YouXianMing/iOS-Des ...
- iOS设计模式 - 中介者
iOS设计模式 - 中介者 原理图 说明 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 注:中介者对象本身没有复用价值 ...
随机推荐
- laravel 报错htmlspecialchars() expects parameter 1 to be string, object given
翻译过来就是 期望参数1是字符串 意思就是说变量为数组,应以数组的方式输出 @foreach($xxx as $k=>$y) {{$k}}{{$y}} @endforeach
- js 判断当前操作系统 ios, android, 电脑端
一 . js判断移动端的操作系统(ios或Android) $(function () { var u = navigator.userAgent; var isAndroid = u.index ...
- 普通组件定义渲染和render渲染组件的区别(三)
普通方式定义组件和效果: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- D. Pair Of Lines( Educational Codeforces Round 41 (Rated for Div. 2))
#include <vector> #include <iostream> #include <algorithm> using namespace std; ty ...
- HTML--使用重置按钮,重置表单信息
当用户需要重置表单信息到初始时的状态时,比如用户输入“用户名”后,发现书写有误,可以使用重置按钮使输入框恢复到初始状态.只需要把type设置为"reset"就可以. 语法: < ...
- 092 Reverse Linked List II 反转链表 II
反转从位置 m 到 n 的链表.用一次遍历在原地完成反转.例如:给定 1->2->3->4->5->NULL, m = 2 和 n = 4,返回 1->4-> ...
- [未读]编写可测试的JavaScript代码
- HashMap源码及原理
HashMap 简介 底层数据结构分析 JDK1.8之前 JDK1.8之后 HashMap源码分析 构造方法 put方法 get方法 resize方法 HashMap常用方法测试 感谢 changfu ...
- 获取dbf中的表名
因为特殊需要,需要获取dbf数据库中的表的名称.现有 如下解决办法 public List<string> GetTableFields(string path) { List<st ...
- phpMyAdmin 缺少 mcrypt 扩展.请检查 PHP 配置.
原文链接:http://zhidao.baidu.com/link?url=5Y4eT7bcnTHFUtzDMs7mvtsGc7jqbs2yqXG06AP5_6t7wukC7uVozSrbUf7iYl ...