《美團客戶端基于響應式的架構實踐.pdf》由會員分享,可在線閱讀,更多相關《美團客戶端基于響應式的架構實踐.pdf(107頁珍藏版)》請在三個皮匠報告上搜索。
1、美團客戶端基于響應式的架構實踐CONTENTS 大綱TABLE OFEasyReact 和 EasyMVVM 的項目背景EasyReact 技術重點EasyMVVM 架構重點美團客戶端面臨的挑戰美團客戶端架構變遷EasyReact 與 EasyMVVM 的初衷EasyReact 和 EasyMVVM 的項目背景EasyReact 和 EasyMVVM 的項目背景美團客戶端面臨的挑戰代碼體量達到數百萬代碼行數十個團隊協同開發迭代周期越來越快產品質量要求越來越高EasyReact 和 EasyMVVM 的項目背景美團客戶端面臨的挑戰代碼質量代碼復用迭代流程架構美團客戶端面臨的挑戰美團客戶端架構變遷
2、EasyReact 與 EasyMVVM 的初衷EasyReact 和 EasyMVVM 的項目背景EasyReact 和 EasyMVVM 的項目背景美團客戶端架構變遷0104050302簡易形態 MVC結構美團AppEasyReact 和 EasyMVVM 的項目背景美團客戶端架構變遷0104050302業務拆分架構Base LibraryCustomUIKitNetworkFoundationCryptoBase Business SDKAccount SDKPayment SDKPush SDKShare SDKTuangouWaimaiMovieHotelEasyReact 和 Ea
3、syMVVM 的項目背景美團客戶端架構變遷0104050302響應式引入 基于 ReactiveCocoaEasyReact 和 EasyMVVM 的項目背景美團客戶端架構變遷0104050302MVVM 架構(基于ReactiveCocoa)ModelViewModelViewEasyReact 和 EasyMVVM 的項目背景美團客戶端架構變遷0104050302MVVM+模塊化架構復用模塊復用模塊復用模塊美團客戶端面臨的挑戰美團客戶端架構變遷EasyReact 與 EasyMVVM 的初衷EasyReact 和 EasyMVVM 的項目背景EasyReact 和 EasyMVVM 的項目
4、背景EasyReact 與 EasyMVVM 的初衷讓人又愛又恨的 ReactiveCocoa概念煩雜調試困難易出錯風格不統一EasyReact 和 EasyMVVM 的項目背景EasyReact 與 EasyMVVM 的初衷讓人又愛又恨的 ReactiveCocoaFRP函數式編程的天然門檻基于 OOP 設計的響應式編程框架EasyReact 和 EasyMVVM 的項目背景EasyReact 與 EasyMVVM 的初衷RP基于 OOP 設計的響應式編程框架簡單、易用EasyReact 和 EasyMVVM 的項目背景EasyReact 與 EasyMVVM 的初衷RPForMVVMMod
5、elViewModelView理解不一致層次劃分不明風格不統一缺乏框架支持EasyReact 和 EasyMVVM 的項目背景EasyReact 與 EasyMVVM 的初衷FrameworkMVVM統一的 MVVM 框架簡單、易用豐富的工具支持CONTENTS 大綱TABLE OFEasyReact 和 EasyMVVM 的項目背景EasyReact 技術重點EasyMVVM 架構重點聲明式編程中的響應式編程基于圖和面向對象的 EasyReact主流框架對比EasyReact 技術重點EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程聲明式編程約
6、束式編程DSL函數式編程邏輯式編程EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程準備環境監測是否成功?協調解決執行環節開始結束EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程父親家庭母親孩子們+登記家庭(父親、母親)-搬家(新地址)住址省地址市街道+登記地址-地址更名樓牌號職級編程語言-編碼-加班程序員年齡人性別-結婚(配偶)-成長EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程父親家庭母親孩子們+登記家庭(父親、母親)-搬家(新地址)住址年齡人性別
7、-結婚(配偶)-成長省地址市街道+登記地址-地址更名樓牌號職級編程語言-編碼-加班程序員可表示地址的-地址更名-獲取地址信息生產日期機器人型號-固件升級-充電可表示人的-獲取信息-吃飯EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程y=f(x)a=b.method(c)狀態1狀態2命令EasyReact 技術重點聲明式編程中的響應式編程命令式編程過程式編程面向對象編程面向接口編程聲明式編程約束式編程DSL函數式編程邏輯式編程EasyReact 技術重點聲明式編程中的響應式編程聲明式編程約束式編程DSL函數式編程邏輯式編程給定約束、范圍得到結果約束
8、計算框架UIEdgeInsets padding=UIEdgeInsetsMake(10,10,10,10);view1 mas_makeConstraints:(MASConstraintMaker*make)make.top.equalTo(superview.mas_top).with.offset(padding.top);/with is an optional semantic fillermake.left.equalTo(superview.mas_left).with.offset(padding.left);make.bottom.equalTo(superview.mas
9、_bottom).with.offset(-padding.bottom);make.right.equalTo(superview.mas_right).with.offset(-padding.right);約束編程(Constraint programming)是一種編程典范,在這種編程范式中,變量之間的關系是以約束的形式陳述(組織)的。這些關系(約束)和命令式編程語言元素不同的是:它們并非明確說明了要去執行的步驟中的某一步,而是規范其解的一些屬性。這樣看來,約束編程是一種聲明式的編程范式。維基百科“EasyReact 技術重點聲明式編程中的響應式編程聲明式編程約束式編程DSL函數式編程
10、邏輯式編程GPLDSLvsSQL領域特定語言指的是專注于某個應用程序領域的計算機語言。又譯作領域專用語言。不同于普通的跨領域通用計算機語言(GPL),領域特定語言只用在某些特定的領域。比如用來顯示網頁的 HTML 語言,以及 Emacs 所使用的 Emac LISP 語言。維基百科“EasyReact 技術重點聲明式編程中的響應式編程聲明式編程約束式編程DSL函數式編程邏輯式編程DSL內嵌 DSL外部 DSLplatform:ios,9.0inhibit_all_warnings!target MyApp do pod ObjectiveSugar,0.5 target MyAppTests
11、do inherit!:search_paths pod OCMock,2.0.1 endendpost_install do|installer|installer.pods_project.targets.each do|target|puts#target.name endendDROP TABLE IF EXISTS table_test_one;CREATE TABLE table_test_one(id int(11)NOT NULL AUTO_INCREMENT,student_no varchar(10)NOT NULL,student_name varchar(10)NOT
12、NULL,subject_no varchar(10)NOT NULL,subject_name varchar(10)NOT NULL,score int(11)NOT NULL,PRIMARY KEY(id)ENGINE=InnoDB DEFAULT CHARSET=utf8;EasyReact 技術重點聲明式編程中的響應式編程聲明式編程約束式編程DSL函數式編程邏輯式編程函數式編程,特別是純函數式編程,嘗試最小化狀態帶來的副作用,因此被認為是聲明式的。大多數函數式編程語言,例如 Scheme、Clojure、Haskell、OCaml、Standard ML和Unlambda,允許副作用
13、的存在。維基百科“EasyReact 技術重點聲明式編程中的響應式編程聲明式編程約束式編程DSL函數式編程邏輯式編程邏輯編程(邏輯程序設計)是種編程典范,它設置答案須匹配的規則來解決問題,而非設置步驟來解決問題。過程是 事實+規則=結果。不同的方法,可以看 Inductive logic programming。維基百科“規則事實friend(X,Y):-likes(X,Y),likes(Y,X).human(kate).human(bill).likes(kate,bill).舉例(sort)q:-L=33,18,2,77,18,66,9,25,(sortcsj(L,P),write(P),
14、nl).sortcsj(L,S):-permutation(L,S),ordered(S).ordered().ordered(_|).ordered(A|B|T):-A=Observable in if query.isEmpty return.just()return searchGitHub(query).catchErrorJustReturn().observeOn(MainScheduler.instance)A1BC2673=B2+C2聲明式編程中的響應式編程基于圖和面向對象的 EasyReact主流框架對比EasyReact 技術重點EasyReact 技術重點基于圖和面向對象
15、的 EasyReact基于圖的數據結構面向對象的設計使用示例EasyReact 技術重點基于圖和面向對象的 EasyReact基于圖的數據結構nodenodenodenodenodenodenodenodenodenodenodenodeedgeedgeedgeedgeedgeedgeedgeedgeedgeedgeedgeedgeEasyReact 技術重點基于圖和面向對象的 EasyReact基于圖的數據結構node anode bnode cnode enode gnode hnode ilistener clistener dnode dlistener blistener amapl
16、inklinklistened byflatten mapfiltertakelistened bycombinelistened bylistened bycombineEasyReact 技術重點基于圖和面向對象的 EasyReact基于圖的數據結構面向對象的設計使用示例EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計Nodevalue:TupstreamTransformsdownstreamTransforms(weak)value()-TlistenEdges(weak)Edgefrom()-NodesetFrom(Node)setTo(ToType)
17、to()-ToTypenext(FromItemType)MutableNode:Nodevalue:TupstreamTransformsdownstreamTransforms(weak)listenEdges(weak)Transform :EdgeFromItemType,Nodevalue()-TsetValue(T)from()-NodesetFrom(Node)setTo(Node)to()-NodeListenEdge :Edgenext(FromItemType)from()-NodesetFrom(Node)setTo(ToType)to()-ToTypenext(From
18、ItemType)setTo(ToType)to()-ToType類型定義EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計Nodevalue:TupstreamTransformsdownstreamTransforms(weak)value()-TlistenEdges(weak)EdgeMutableNode:Nodevalue:TupstreamTransformsdownstreamTransforms(weak)listenEdges(weak)Transform :EdgeFromItemType,Nodevalue()-TsetValue(T)Li
19、stenEdge :EdgeSomeTransform :TransformNode,Nodefrom:Nodeto:Node(weak)next(FromItemType)構建連接EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計Nodevalue:TupstreamTransformsdownstreamTransforms(weak)value()-TlistenEdges(weak)EdgeMutableNode:Nodevalue:TupstreamTransformsdownstreamTransforms(weak)listenEdges(weak)
20、Transform :EdgeFromItemType,Nodevalue()-TsetValue(T)ListenEdge :EdgeSomeTransform :TransformNode,Nodefrom:Nodeto:Node(weak)next(FromItemType)SomeListenEdge :ListenEdgeNode,Anyfrom:Nodenext(FromItemType)AnyObject+ListenExtensionto:Any(weak)listenEdges構建監聽EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計Nodeva
21、lue:TupstreamTransformsdownstreamTransforms(weak)value()-TlistenEdges(weak)MutableNode:Nodevalue:TupstreamTransformsdownstreamTransforms(weak)listenEdges(weak)value()-TsetValue(T)SomeTransform :TransformNode,Nodefrom:Nodeto:Node(weak)next(FromItemType)SomeListenEdge :ListenEdgeNode,Anyfrom:Nodenext(
22、FromItemType)to:Any(weak)Weak 鏈條作為傳播鏈條數據流動EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計Nodevalue:TupstreamTransformsdownstreamTransforms(weak)value()-TlistenEdges(weak)MutableNode:Nodevalue:TupstreamTransformsdownstreamTransforms(weak)listenEdges(weak)value()-TsetValue(T)SomeTransform :TransformNode,Node
23、from:Nodeto:Node(weak)next(FromItemType)SomeListenEdge :ListenEdgeNode,Anyfrom:Nodenext(FromItemType)AnyObject+ListenExtensionto:Any(weak)listenEdgesStrong 鏈條作為內存管理內存管理EasyReact 技術重點基于圖和面向對象的 EasyReact面向對象的設計類型定義構建連接構建監聽數據流動內存管理EasyReact 技術重點基于圖和面向對象的 EasyReact基于圖的數據結構面向對象的設計使用示例EasyReact 技術重點基于圖和面向
24、對象的 EasyReact使用示例創建節點let nodeA=MutableNode(1)let nodeB=Node()創建變換連接節點創建監聽連接監聽者let transform=MapTransform$0*2 transform.set(from:nodeA)transform.set(to:nodeB)let listenEdge=BlockListenEdge print($0)nodeB.listened(by:self).with(listenEdge)改變節點值nodeA.set(5)EasyReact 技術重點基于圖和面向對象的 EasyReact使用示例創建節點let n
25、odeA=MutableNode(1)創建變換連接節點創建監聽連接監聽者改變節點值變換衍生便捷監聽let nextNode=nodeA.map$0*3 nextNode.listened(by:self).with print($0)聲明式編程中的響應式編程基于圖和面向對象的 EasyReact主流框架對比EasyReact 技術重點EasyReact 技術重點主流框架對比易用性性能排錯能力EasyReact 技術重點主流框架對比易用性性能排錯能力EasyReact 技術重點主流框架對比易用性對比RAC&RxSwiftImmutableCold signal&Hot signalSignal,
26、Producer and SubjectFunctor,Applicative,MonadEasyReactMutableLink,syncNode,Edge,ListenerOOP designedEasyReact 技術重點主流框架對比易用性性能排錯能力EasyReact 技術重點主流框架對比性能對比0125,000,000250,000,000375,000,000500,000,000listenermapfilterfattenMap combinezipmergesyncToEasyReact(Objc)ReactiveCocoaEasyReact 技術重點主流框架對比易用性性能排
27、錯能力EasyReact 技術重點主流框架對比排錯能力ReactiveCocoa 調試堆棧EasyReact 技術重點主流框架對比排錯能力ReactiveCocoa 調試堆棧5次變換 50層堆棧 堆棧內容無法參考EasyReact 技術重點主流框架對比排錯能力EasyReact 調試堆棧EasyReact 技術重點主流框架對比排錯能力EasyReact 調試堆棧5次變換 10層堆棧 堆棧內容與變換相符EasyReact 技術重點主流框架對比排錯能力追溯CONTENTS 大綱TABLE OFEasyReact 和 EasyMVVM 的項目背景EasyReact 技術重點EasyMVVM 架構重點
28、EasyMVVM 框架簡介EasyMVVM 解決的問題Rubik 模塊化方案EasyMVVM 架構重點EasyMVVM架構重點EasyMVVM 框架簡介整體架構EasyFoundationSequenceThread-safe CollectionTupleEnumerateUseful BlocksEasyReactNodeEdgeTransformListenEdgeMutable NodeNode OperationCancelableEasyActionActionOperationOperations operationOperationQueueEasyNetworkService
29、ManagerServicePluginsEasyMVVMBinderContainerEventHandlerModelModelCenterUIKit CategoryRubik FrameworkCellPresentationContainerViewContentViewGridViewListViewRubikView ControllerPresentation ProviderContentView ControllerListView ControllerGridView ControllerEasyDebug ToolboxSqlite3WebSocketKituraVis
30、.jsEasyMVVM 架構重點EasyMVVM 框架簡介EasyMVVM 解決的問題Rubik 模塊化方案EasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定聚合類視圖的綁定頁面間的依賴EasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定ViewViewModelModelBindingInvokeEasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定ViewViewModelModelBindingInvoke(VC)NodeEventHandlerNodeEventHandlerOperationResultErrorEasyMVVM 架構重點Ea
31、syMVVM 解決的問題聲明式的綁定ViewViewModelModel(VC)NodeEventHandlerNodeEventHandlerOperationResultErrorNodeNodeNodeEasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定優惠買單PaymentVCrootView consumeTextField textNode QRCodeButton clickEvent excludeCheckbox checkedNode discountLabel textNode couponButton clickEvent paymentLabel tex
32、tNode conformButton clickEvent didAppearEvent errorMessagePaymentVMconsume:Node showQR:Handler isExclude:Node discount:Node coupone:Handler payment:Node conform:Handler fetchDiscount:Handler errorMsg:NodePaymentModelmerchantID:Node gotoQR:Operation result error conform:Operation result error discoun
33、t:Operation result errorEasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定 override func bindView(using binder:Binder)super.bindView(using:binder)binder.bind(mainVM.consume,with:consumeTextField.ezm.textNode)binder.bind(QRCodeButton.ezm.clickEvent,with:mainVM.showQR)binder.bind(mainVM.isExclude,with:excludeCheckbox.
34、checkedNode)binder.bind(discountLabel.ezm.textNode,with:mainVM.discount)binder.bind(couponButton.ezm.clickEvent,with:mainVM.coupone)binder.bind(paymentLabel.ezm.textNode,with:mainVM.payment)binder.bind(conformButton.ezm.clickEvent,with:mainVM.comform)binder.bind(ezm.didAppearEvent,with:mainVM.fetchD
35、iscount)binder.bind(ezm.errorMessage,with:mainVM.errorMsg)EasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定聚合類視圖的綁定頁面間的依賴EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 演示與實際的差異vsEasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 固定頁面與聚合頁面的差異vs優惠買單EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 UITableView 與 MVVMclass TableViewController:UIViewControlle
36、r,UITableViewDelegate,UITableViewDataSource IBOutlet var tableView:UITableView!let dataSource=(title:a,height:17),(title:b,height:20),(title:c,height:17),(title:d,height:22)override func viewDidLoad()super.viewDidLoad()tableView.register(UITableViewCell.self,forCellReuseIdentifier:reusableCell)func
37、tableView(_ tableView:UITableView,numberOfRowsInSection section:Int)-Int return dataSource.count func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-UITableViewCell let cell=tableView.dequeueReusableCell(withIdentifier:reusableCell,for:indexPath)cell.textLabel?.text=dataSourcein
38、dexPath.row.title return cell func tableView(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-CGFloat return CGFloat(dataSourceindexPath.row.height)func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)/do something EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 UITableView 與 MVV
39、Mclass TableViewController:UIViewController,UITableViewDelegate,UITableViewDataSource IBOutlet var tableView:UITableView!let dataSource=(title:a,height:17),(title:b,height:20),(title:c,height:17),(title:d,height:22)override func viewDidLoad()super.viewDidLoad()tableView.register(UITableViewCell.self
40、,forCellReuseIdentifier:reusableCell)func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int)-Int return dataSource.count func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-UITableViewCell let cell=tableView.dequeueReusableCell(withIdentifier:reusableCell,for:i
41、ndexPath)cell.textLabel?.text=dataSourceindexPath.row.title return cell func tableView(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-CGFloat return CGFloat(dataSourceindexPath.row.height)func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)/do something 數據變化無法傳遞回調方
42、式無法聲明回調分散代碼混亂EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 多類型異構場景class DiscoverViewController:UIViewController,UITableViewDelegate,UITableViewDataSource IBOutlet var tableView:UITableView!let dataSource:News=.Video(title:video,url:xxx),.Picture1(title:h2,image:yyy,description:desc),.Picture1(title:h3,image:z
43、zz,description:Desc),.Picture3(title:ps,images:aaa,bbb,ccc),.BigPicture(title:bigger,image:fff),.Video(title:new video,url:ggg)override func viewDidLoad()super.viewDidLoad()tableView.register(VideoCell.self,forCellReuseIdentifier:Video)tableView.register(Picture1Cell.self,forCellReuseIdentifier:Pict
44、ure1)tableView.register(Picture3Cell.self,forCellReuseIdentifier:Picture3)tableView.register(BigPictureCell.self,forCellReuseIdentifier:BigPicture)func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int)-Int return dataSource.count func tableView(_ tableView:UITableView,cellForRowAt
45、 indexPath:IndexPath)-UITableViewCell switch dataSourceindexPath.row case.Video(let title,let url):let cell=tableView.dequeueReusableCell(withIdentifier:Video,for:indexPath)as!VideoCell cell.textLabel?.text=title cell.url=url return cell case.Picture1(let title,let image,let description):let cell=ta
46、bleView.dequeueReusableCell(withIdentifier:Picture1,for:indexPath)as!Picture1Cell cell.textLabel?.text=title cell.imageURL=image cell.desc=description return cell case.Picture3(let title,let images):let cell=tableView.dequeueReusableCell(withIdentifier:Picture3,for:indexPath)as!Picture3CellEasyMVVM
47、架構重點EasyMVVM 解決的問題聚合類視圖的綁定 多類型異構場景 let dataSource:News=.Video(title:video,url:xxx),.Picture1(title:h2,image:yyy,description:desc),.Picture1(title:h3,image:zzz,description:Desc),.Picture3(title:ps,images:aaa,bbb,ccc),.BigPicture(title:bigger,image:fff),.Video(title:new video,url:ggg)override func vie
48、wDidLoad()super.viewDidLoad()tableView.register(VideoCell.self,forCellReuseIdentifier:Video)tableView.register(Picture1Cell.self,forCellReuseIdentifier:Picture1)tableView.register(Picture3Cell.self,forCellReuseIdentifier:Picture3)tableView.register(BigPictureCell.self,forCellReuseIdentifier:BigPictu
49、re)func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int)-Int return dataSource.count func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-UITableViewCell switch dataSourceindexPath.row case.Video(let title,let url):let cell=tableView.dequeueReusableCell(withId
50、entifier:Video,for:indexPath)as!VideoCell cell.textLabel?.text=title cell.url=url return cell case.Picture1(let title,let image,let description):let cell=tableView.dequeueReusableCell(withIdentifier:Picture1,for:indexPath)as!Picture1Cell cell.textLabel?.text=title cell.imageURL=image cell.desc=descr
51、iption return cell case.Picture3(let title,let images):let cell=tableView.dequeueReusableCell(withIdentifier:Picture3,for:indexPath)as!Picture3Cell cell.textLabel?.text=title cell.imageURLs=images return cell case.BigPicture(let title,let image):let cell=tableView.dequeueReusableCell(withIdentifier:
52、BigPicture,for:indexPath)as!BigPictureCell cell.textLabel?.text=title cell.imageURL=image return cell func tableView(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-CGFloat switch dataSourceindexPath.row case.Video(_,_):return VideoCell.height case.Picture1(_,_,_):return Picture1Cell.hei
53、ght case.Picture3(_,_):return Picture3Cell.height case.BigPicture(_,_):return BigPictureCell.heightEasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 多類型異構場景 let cell=tableView.dequeueReusableCell(withIdentifier:Video,for:indexPath)as!VideoCell cell.textLabel?.text=title cell.url=url return cell case.Picture1(let
54、title,let image,let description):let cell=tableView.dequeueReusableCell(withIdentifier:Picture1,for:indexPath)as!Picture1Cell cell.textLabel?.text=title cell.imageURL=image cell.desc=description return cell case.Picture3(let title,let images):let cell=tableView.dequeueReusableCell(withIdentifier:Pic
55、ture3,for:indexPath)as!Picture3Cell cell.textLabel?.text=title cell.imageURLs=images return cell case.BigPicture(let title,let image):let cell=tableView.dequeueReusableCell(withIdentifier:BigPicture,for:indexPath)as!BigPictureCell cell.textLabel?.text=title cell.imageURL=image return cell func table
56、View(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-CGFloat switch dataSourceindexPath.row case.Video(_,_):return VideoCell.height case.Picture1(_,_,_):return Picture1Cell.height case.Picture3(_,_):return Picture3Cell.height case.BigPicture(_,_):return BigPictureCell.height func tableVi
57、ew(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)switch dataSourceindexPath.row case.Video(_,_):/do something case.Picture1(_,_,_):/do something case.Picture3(_,_):/do something case.BigPicture(_,_):/do something EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 EasyMVVM 解決的問題跟蹤變化的容器聲明化的聚合類視圖異構去除swit
58、ch-caseEasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 跟蹤變化的容器EasyContainer線程安全變化跟蹤變化具體類型索引變化元素數量變化變化類型與UITableView兼容支持事務EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 聲明化的聚合類視圖ListViewGridViewEasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 聲明化的聚合類視圖class ListView:UIView let dataSource:NodeContainer func pattern(forCellClass cellClas
59、s:CellClass.Type,viewModelIs vmClass:VM.Type,pattern:(VM)-Bool,binding:escaping(Binder,CellClass,VM)-Void)EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 聲明化的聚合類視圖class GridView:UIView let dataSource:NodeContainer let column:Node let itemHeight:Node func pattern(forCellClass cellClass:CellClass.Type,viewModelIs
60、 vmClass:VM.Type,pattern:(VM)-Bool,binding:escaping(Binder,CellClass,VM)-Void)EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 class GridViewController:EasyViewController IBOutlet var gridView:GridView!IBOutlet var resetButton:UIButton!IBOutlet var addButton:UIButton!/.let mainVM=GridMainVM()override func bindVi
61、ew(using binder:Binder)super.bindView(using:binder)gridView.pattern(forCellClass:GridItemCell.self,viewModelIs:GridItemVM.self,patternBlock:matchAllViewModels()(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.text)binder.bind(gridView.dataSource,with:mainVM.items)binder.bind(resetB
62、utton.ezm.clickEvent,with:mainVM.resetItmes)binder.bind(addButton.ezm.clickEvent,with:mainVM.addItems)/.聲明化的聚合類視圖EasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 class DiscoverViewController:EasyViewController IBOutlet var listView:ListView!let mainVM=DiscoverListViewModel()override func bindView(using binder:Bi
63、nder)super.bindView(using:binder)listView.pattern(forCellClass:VideoCell.self,viewModelIs:VideoVM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.urlNode,with:vm.videoURL)listView.pattern(forCellClass:Picture1Cell.self,viewModelIs:Picture1VM.self )(bin
64、der,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.imageURL,with:vm.imageURL)binder.bind(cell.desc,with:vm.desc)listView.pattern(forCellClass:Picture3Cell.self,viewModelIs:Picture3VM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)bin
65、der.bind(cell.imageURLs,with:vm.imageURLs)listView.pattern(forCellClass:BigPictureCell.self,viewModelIs:BigPictureVM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.imageURL,with:vm.imageURL)binder.bind(ezm.willAppearEvent,with:mainVM.reloadDiscoverLis
66、t)異構去除 switch-caseEasyMVVM 架構重點EasyMVVM 解決的問題聚合類視圖的綁定 class DiscoverViewController:EasyViewController IBOutlet var listView:ListView!let mainVM=DiscoverListViewModel()override func bindView(using binder:Binder)super.bindView(using:binder)listView.pattern(forCellClass:VideoCell.self,viewModelIs:Video
67、VM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.urlNode,with:vm.videoURL)listView.pattern(forCellClass:Picture1Cell.self,viewModelIs:Picture1VM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.imageURL,
68、with:vm.imageURL)binder.bind(cell.desc,with:vm.desc)listView.pattern(forCellClass:Picture3Cell.self,viewModelIs:Picture3VM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.imageURLs,with:vm.imageURLs)listView.pattern(forCellClass:BigPictureCell.self,vie
69、wModelIs:BigPictureVM.self )(binder,cell,vm)in binder.bind(cell.textLabel.ezm.textNode,with:vm.title)binder.bind(cell.imageURL,with:vm.imageURL)binder.bind(ezm.willAppearEvent,with:mainVM.reloadDiscoverList)異構去除switch-caseclass DiscoverViewController:UIViewController,UITableViewDelegate,UITableViewD
70、ataSource IBOutlet var tableView:UITableView!let dataSource:News=.Video(title:video,url:xxx),.Picture1(title:h2,image:yyy,description:desc),.Picture1(title:h3,image:zzz,description:Desc),.Picture3(title:ps,images:aaa,bbb,ccc),.BigPicture(title:bigger,image:fff),.Video(title:new video,url:ggg)overrid
71、e func viewDidLoad()super.viewDidLoad()tableView.register(VideoCell.self,forCellReuseIdentifier:Video)tableView.register(Picture1Cell.self,forCellReuseIdentifier:Picture1)tableView.register(Picture3Cell.self,forCellReuseIdentifier:Picture3)tableView.register(BigPictureCell.self,forCellReuseIdentifie
72、r:BigPicture)func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int)-Int return dataSource.count func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-UITableViewCell switch dataSourceindexPath.row case.Video(let title,let url):let cell=tableView.dequeueReusableC
73、ell(withIdentifier:Video,for:indexPath)as!VideoCell cell.textLabel?.text=title cell.url=url return cell case.Picture1(let title,let image,let description):let cell=tableView.dequeueReusableCell(withIdentifier:Picture1,for:indexPath)as!Picture1Cell cell.textLabel?.text=title cell.imageURL=image cell.
74、desc=description return cell case.Picture3(let title,let images):let cell=tableView.dequeueReusableCell(withIdentifier:Picture3,for:indexPath)as!Picture3Cell cell.textLabel?.text=title cell.imageURLs=images return cell case.BigPicture(let title,let image):let cell=tableView.dequeueReusableCell(withI
75、dentifier:BigPicture,for:indexPath)as!BigPictureCell cell.textLabel?.text=title cell.imageURL=image return cell func tableView(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-CGFloat switch dataSourceindexPath.row case.Video(_,_):return VideoCell.height case.Picture1(_,_,_):return Pictur
76、e1Cell.height case.Picture3(_,_):return Picture3Cell.height case.BigPicture(_,_):return BigPictureCell.height func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath)switch dataSourceindexPath.row case.Video(_,_):/do something case.Picture1(_,_,_):/do something case.Picture3(_,_):/
77、do something case.BigPicture(_,_):/do something 代碼對比EasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定聚合類視圖的綁定頁面間的依賴EasyMVVM 架構重點EasyMVVM 解決的問題頁面間的依賴ViewViewModelModelBindingInvokeEasyMVVM 架構重點EasyMVVM 解決的問題頁面間的依賴ViewViewModelModelViewViewModelModelViewViewModelModelEasyMVVM 架構重點EasyMVVM 解決的問題頁面間的依賴ViewVM1Model1View
78、Model3ViewVM4Model2VM2VM2VM3EasyMVVM 架構重點EasyMVVM 解決的問題頁面間的依賴MerchantList PageMerchantList ViewModelMerchantList ModelMerchantDetail PageMerchantDetail ModelMerchantDetail ViewModelEasyMVVM 架構重點EasyMVVM 解決的問題聲明式的綁定聚合類視圖的綁定頁面間的依賴EasyMVVM 架構重點EasyMVVM 框架簡介EasyMVVM 解決的問題Rubik 模塊化方案EasyMVVM 架構重點Rubik 模塊
79、化方案為什么需要模塊化方案Rubik 模塊化系統EasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案代碼復用復用模塊復用模塊復用模塊EasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案代碼復用分段場景EasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案代碼復用分段場景不同類型聚合視圖整合輪播圖1x5大分類2x5小分類2x2推薦區單頁廣告區EasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案Rubik 模塊化系統RubikEasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案Rubik 模塊化系統RubikCubeEa
80、syMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案Rubik 模塊化系統RubikViewCubePresentationListViewGridViewContentView?CustomViewEasyMVVM 架構重點Rubik 模塊化方案為什么需要模塊化方案Rubik 模塊化系統 rubikView.cubs.value.add(listView)rubikView.cubs.value.add(gridView)rubikView.cubs.value.add(ContentView(uiView)CONTENTS 大綱TABLE OFEasyReact 和 EasyMVVM 的項目背景EasyReact 技術重點EasyMVVM 架構重點寫在最后的話“EasyReact OC 版本即將開源!美團平臺技術團隊“EasyReact Swift 開發中 EasyReact JS 計劃中 其他 Easy 系列陸續開源 美團平臺技術團隊Thanks Q&A