- 快召唤伙伴们来围观吧
- 微博 QQ QQ空间 贴吧
- 文档嵌入链接
- 复制
- 微信扫一扫分享
- 已成功复制到剪贴板
阿里UC 王文槿 - 《从Observer到Observable:使用Functional+Swift提升复杂iOS项目的可维
展开查看详情
1 . 从 Observer 到 Observable 使⽤用 Functional Swift 提升复杂 iOS 项⽬目的可维护性 演讲者/王⽂文槿
2 . ⾃自我介绍 • 王⽂文槿 / aaaron7 / 莲叔 • 2012 - 2016:创业,iOS + Py 后端 • 2016 - ⾄至今 :UC,iOS + Weex + ⾳音视频 • 函数式编程爱好者
3 . 摘要 • 为什什么需要 Functional thinking? • Functional 经典应⽤用:实现简单的 Observable 系统 • 解决⼀一些实际问题 • 背后隐藏的设计模式 • Q&A
4 .为什什么需要 Functional thinking?
5 .异常处理理的完备性问题
6 . OC时代的异常处理理 - (void)statVideoPlay:(NSString *)videoUrl{ VideoInfo *info = self.videos[videoUrl]; [StatUtility uploadStatisInfo:@{@"video_title":info.videoTitle}]; }
7 . OC时代的异常处理理 - (void)statVideoPlay:(NSString *)videoUrl{ assert(videoUrl != nil); VideoInfo *info = self.videos[videoUrl]; [StatUtility uploadStatisInfo:@{@"video_title":info.videoTitle}]; }
8 . OC时代的异常处理理 - (void)statVideoPlay:(NSString *)videoUrl{ assert(videoUrl != nil); VideoInfo *info = self.videos[videoUrl]; if (info) { [StatUtility uploadStatisInfo:@{@"video_title":info.videoTitle}]; } }
9 . OC时代的异常处理理 - (void)statVideoPlay:(NSString *)videoUrl{ assert(videoUrl != nil); VideoInfo *info = self.videos[videoUrl]; if (info && info.videoTitle) { [StatUtility uploadStatisInfo:@{@"video_title":info.videoTitle}]; } }
10 . OC时代的异常处理理 - (void)statVideoPlay:(NSString *)videoUrl{ assert(videoUrl != nil); VideoInfo *info = self.videos[videoUrl]; if (info && info.videoTitle) { [StatUtility uploadStatisInfo:@{@"video_title":info.videoTitle}]; //... //... //... [StatUtility uploadStatisInfo:@{@"video_category":info.videoCategory}]; //... //... } }
11 .⼼心累,想哭
12 . Swift 时代 func statVideoPlay(videoUrl : String?){ if let url = videoUrl{ let videoInfo = self.videos[url] if let info = videoInfo{ if let title = info.title{ StatUtility.uploadStatisInfo(statInfo: ["videoTitle":title]) } } } }
13 .还是⼼心累,还是想哭
14 .异常处理理的完备性问题 异常处理理 title : String? [“video_title” : title] 本质 a? f : a -> b
15 .异常处理理的完备性问题 异常处理理 title : String? [“video_title” : title] 本质 a? f : a -> b f 也可能失败
16 .异常处理理的完备性问题 异常处理理 title : String? [“video_title” : title] 本质 a? f : a -> b? 是否有标准化的可能?
17 .Functional Thinking g a? f : a -> b? g: (input : a?, f : (a) -> b?) -> b? if input {return f(input)} else {return nil}
18 . 如果有神奇的 g func statVideoPlay(videoUrl : String?){ let info:VideoInfo? = g(input: videoUrl) { self.videos[$0] } let title:String? = g(input: info) { $0.title } _ = g(input: title, f: { (x) -> String? in StatUtility.uploadStatisInfo(statInfo: ["videoTitle":x]) return nil }) } 通过 g,⾃自始⾄至终没有任何判空,但代码是安全的。
19 . hmmm,改进⼀一下 把 g 扔到 optional 的 extension ⾥里里 func statVideoPlay(videoUrl : String?){ _ = videoUrl .g { self.videos[$0] } .g { $0.title } .g { (x) -> String? in StatUtility.uploadStatisInfo(statInfo: ["videoTitle" : x]) return nil } } 进⼀一步消除了了中间变量量
20 . 这个 g,有点眼熟? extension Optional{ func g<b>(f : (Wrapped) -> b?) -> b?{ return self.flatMap {f($0)} } }
21 . 重新认识 flatMap Optional 类型的 flatMap, 本质就是提供了了⼀一个标准化的⽅方式,来实现 Optional Value 到 只接收⾮非 Optional Value 逻辑的绑定
22 . Functional Thinking • 通过抽象来更更好的描述问题 • 本质:⾮非确定性 State -> 确定性 State的转换 • 对于同构的场景提取模型 • 普适的模型: (input : a?, f : (a) -> b?) -> b? • 最终通过符合直觉的⽅方式解决问题 • 链式调⽤用,顺序执⾏行行,⽆无需维护⼀一堆中间变量量和分⽀支逻辑
23 . Functional 经典应⽤用 ⼀一个简单的 Observable 系统
24 . Observable An Observable is an entity that wraps a value and allows to observe the value for changes. PUSH-DRIVEN EVENT MODEL
25 .Observable 的⽅方案选择
26 . 复杂框架所带来的问题 陡峭的Learning Curve ⽆无法低成本在团队推⼴广 最终因编码⻛风格的⼀一致 性等原则导致难产
27 . Observable 的核⼼心 • ⼀一个具备 observe closure 管理理功能的泛型容器器 • ⼏几个操作该容器器的核⼼心⽅方法(subscribleNext/bind/map/filter) • ⼀一般⽤用 Signal 表示,因为 value emit 的⾏行行为很像信号 • 具备⾃自研条件,易易于落地
28 . 动动⼿手 public class Signal<a> : NSObject { typealias SignalToken = Int typealias Subscriber = (a) -> Void var subscribers = [SignalToken:Subscriber]() closure 容器器 public private(set) var value : a? let queue = DispatchQueue(label: "com.swift.let.token") init(value : a) { 订阅更更新的接⼝口 self.value = value } 语法糖,直接绑定两个 Signal 的值(type⼀一致) public func subscribeNext(hasInitialValue:Bool = false, subscriber : @escaping (a) -> Void) -> SignalToken public func bind(signal : Signal<a>) -> SignalToken public func update(_ value : a) } 更更新 value,并逐个调⽤用所有 closure
29 . Playground let xSignal = Signal(value: 0) let ySignal = Signal(value: 1) _ = xSignal.bind(signal: ySignal) _ = xSignal.subscribeNext { (x) in print("got \(x) in xsignal") } _ = ySignal.subscribeNext(subscriber: { (x) in print("got \(x) in ysignal”) }) xSignal.update(33) got 33 in xsignal got 33 in ysignal