Swift利用协议优化NSNotificationCenter
NSNotificationCenter存在的问题
通知没有统一的命名格式
对于通知的命名没有强制的要求,一个项目里可能有多种不同的命名规则。比如:
|
1
2
3
4
5
6
|
class Barista { let notification = "coffeeMadeNotification"}class Trainee { let coffeeMadeNotificationName = "Coffee Made"} |
通知名称可能冲突
因为对于通知名称没有限制,可能在不同的对象定义了同样的通知名,这样会导致难以意料的bug。
|
1
2
3
4
5
6
|
class Barista { let notification = "coffeeMadeNotification"}class Trainee { let coffeeMadeNotificationName = "coffeeMadeNotification"} |
通知的名称是字符串
字符串真的太危险了,很容易出现打错的情况。
|
1
2
|
NSNotificationCenter.defaultCenter() .postNotificationName("coffeeMadNotfication") |
利用protocol的解决方案
我们通过设计一个protocol来解决上面提到的问题。
|
1
|
protocol Notifier { } |
通过枚举统一通知名称
给这个协议增加一个关联类型:
|
1
2
3
|
protocol Notifier { associatedType Notification: RawRepresentable} |
所有要发送通知的对象或者结构体都要实现Notifier这个协议,然后提供一个实现了RawRepresentable的类型。其实就是一个字符串枚举。
|
1
2
3
4
5
6
|
class Barista : Notifier { enum Notification : String { case makingCoffee case coffeeMade }} |
这样就可以有一个统一的方式获取通知名称:
|
1
2
3
|
let coffeeMade = Barista.Notification.coffeeMade.rawValueNSNotificationCenter.defaultCenter() .postNotificationName(coffeeMade) |
避免通知名称冲突
我们可以为通知添加一个唯一的命名空间(namespace)来避免冲突。这里想到的解决方案是使用实现这个协议的object名称,因为每个object的名称在一个项目里是唯一的。
|
1
2
3
4
5
6
|
let baristaNotification = "\(Barista).\(Barista.Notification.coffeeMade.rawValue)"let traineeNotification = "\(Trainee).\(Trainee.Notification.coffeeMade.rawValue)"// baristaNotification: Barista.coffeeMade// traineeNotification: Trainee.coffeeMade |
但是每个通知都要手动添加就太蛋疼了。我们给这个协议加一个拓展方法来生成唯一的通知名称。因为这个方法只需要内部知道,所以标记为private。
|
1
2
3
4
5
|
public extension Notifier where Notification.RawValue == String { private static func nameFor(notification: Notification) -> String { return "\(self).\(notification.rawValue)" }} |
Notifier的扩展方法
添加观察者
最后一个通知的参数类型就是前面定义的那个枚举类型,这样就不用输入通知名称的字符串。
|
1
2
3
4
5
|
static func addObserver(observer: AnyObject, selector: Selector, notification: Notification) { let name = nameFor(notification) NSNotificationCenter.defaultCenter() .addObserver(observer, selector: selector, name: name, object: nil)} |
这样在使用的时候,在实现协议的object上直接方便的添加观察者:
|
1
|
Barista.addObserver(customer, selector: #selector(Customer.drink(_:)), notification: .coffeeMade) |
发送通知
调用的时候应该是这样的:
|
1
|
Barista.postNotification(.coffeeMade) |
这里利用了swfit的默认参数,object和userinfo设置一个默认的空值。实现如下:
|
1
2
3
4
5
|
static func postNotification(notification: Notification, object: AnyObject? = nil, userInfo: [String : AnyObject]? = nil) { let name = nameFor(notification) NSNotificationCenter.defaultCenter() .postNotificationName(name, object: object, userInfo: userInfo)} |
移除观察
这个实现就不贴了。和前面两个方法类似。调用的时候是这样的:
|
1
|
Barista.removeObserver(customer, notification: .coffeeMade) |
总结
通 过灵活利用swift的语言特性:协议关联类型,协议可以添加默认的方法实现以及方法的默认参数,利用自定义的Notifier协议封装了 NSNotificationCenter的调用方式,解决了传统NSNotificationCenter调用的可能产生的三个潜在风险。
源码:https://github.com/andyyhope/Blog_NSNotificationCenterProtocol
Swift利用协议优化NSNotificationCenter的更多相关文章
- Swift泛型协议的N种用法
They said "you should learn a new language every year," so I learned Swift. Now I learn ...
- Android中利用ViewHolder优化自定义Adapter的典型写法
利用ViewHolder优化自定义Adapter的典型写法 最近写Adapter写得多了,慢慢就熟悉了. 用ViewHolder,主要是进行一些性能优化,减少一些不必要的重复操作.(WXD同学教我的. ...
- 利用Gulp优化部署Web项目[长文慎入]
Gulp Gulp是一款项目自动化的构建工具,与Grunt一样可以通过创建任务(Task)来帮助我们自动完成一些工作流的内容.当然,今天我们的内容并不是讨论这二者的区别,仅仅是介绍介绍如何利用Gulp ...
- 【转】利用TCMalloc优化Nginx的性能
From: http://www.linuxidc.com/Linux/2013-04/83197.html TCMalloc的全称是 Thread-Caching Malloc,是谷歌开发的开源工具 ...
- Objective-C学习笔记 利用协议实现回调函数
来源:http://mobile.51cto.com/iphone-278354.htm Objective-C学习笔记 利用协议实现回调函数是本文要介绍的内容,主要是实现一个显示文字为测试的视图,然 ...
- 利用Swift之协议语法实现页面间的传值功能
随着Swift 新开发语言的发布,又随着Xcode6.0.1的正式发布,利用swift编写iOS代码迫在眉睫,笔者在使用Objective-C开发近三年以来,对这种优雅的语法深感赞叹,下面我将对比式的 ...
- 高速网络下的http协议优化
http协议是基于TCP协议,具备TCP协议的所有功能.但是与一般TCP的长连接不同的是http协议往往连接时间比较短,一个请求一个响应了事.但是总所周知,TCP协议除了具备可靠的传输以外,还有拥塞控 ...
- 利用Select2优化@Html.ListBoxFor显示,学会用MultiSelectList
最近需要用到多选框,Asp.Net MVC自带的@Html.ListBox或@Html.ListBoxFor的显示效果太差,于是找到了Select2进行优化,并正式了解了多选框的操作方法. 首先介绍多 ...
- 窥探Swift之协议(Protocol)和委托代理(Delegate)回调的使用
协议与委托代理回调在之前的博客中也是经常提到和用到的在<Objective-C中的委托(代理)模式>和<iOS开发之窥探UICollectionViewController(四) - ...
随机推荐
- vim 使用
vim有三种模式:输入模式,命令模式,底行模式,使用esc进入命令模式,在命令模式下按英文的冒号,进入底行模式:命令行模式下按i进入输入模式.vim编辑文件是将文件内容复制到缓冲区显示在屏幕上. vi ...
- C#的XML序列化及反序列化
webservice在工作中用到的很多,基本都是以XML格式问通讯内容,其中最关键的就是XML串的序列化及反序列化. XML的运用中有两种信息传递,一种为XML的请求信息,另一种为返回信息,要运用XM ...
- imageNamed和imageWithContentsOfFile区别
在 Apple 官方帮助文档提供了两个加载图片的方法 imageNamed , 其参数为图片的名字 imageWithContentsOfFile , 其参数是图片文件的路径 下面主要是说一下他们的区 ...
- PHP面试题4
在PHP中,当前脚本的名称(不包括路径和查询字符串)记录在预定义变量(1)中:而链接到当前页面的URL记录在预定义变量(2)中. 答:echo $_SERVER['PHP_SELF']; echo $ ...
- c语言中(*p)[n]和*p[n]的区别
写于2016年12月5日. c语言中(*p)[n]表示的数组指针,在该表达式中按照运算的优先级,首先计算()的中*p,在和[n]计算.含义为指向含有n个元素的一维数组. *p[n]表示的是指针数组,在 ...
- UltraEdit 注册机使用说明
请断开网络连接(或直接拔掉网线)后执行: 安装完成后,点击弹出界面的“注册”按钮,然后直接点击“激活”,此时UltraEdit检测到网络断开则弹出界面提示“脱机激活”,此时启动注册机,并将UltraE ...
- ORA-01102 报错解决方法
Problem Explanation: ==================== A database is started in EXCLUSIVE mode by default. Th ...
- VMware如何实现和主机共享网络上网
VMware虚拟机的三种联网方法及原理 一.Brigde--桥接 :默认使用VMnet0 1.原理: Bridge 桥"就是一个主机,这个机器拥有两块网卡,分别处于两个局域网中,同时在& ...
- Node.js-部署【1】-防火墙端口的配置
原来以为,Node.js部署以后,要手动配置防火墙端口,结果不需要,外网可以访问,看来是自动配好了,真是考虑周到,给我一个大大的惊喜.
- 【原】iOS学习之UIApplication及其代理
1. 什么是UIApplication UIApplication 对象是应用程序的象征,不能手动创建,不能 alloc init,一个应用程序只允许 一个 . 每个应用都有自己的 UIApplica ...