iOS應用架構談 開篇
iOS應用架構談 view層的組織和調用方案
iOS應用架構談 網絡層設計方案
iOS應用架構談 本地持久化方案及動態部署html
前言
《iOS應用架構談 開篇》出來以後,不少人來催我趕忙出第二篇。這一篇文章出得至關艱難,由於公司裏的破事兒特別多,我本身又有點私事兒,以致於能用來寫博客的時間不夠充分。java
如今好啦,第二篇出來了。react
當咱們開始設計View層的架構時,每每是這個App尚未開始開發,或者這個App已經發過幾個版本了,而後此時須要作很是完全的重構。ios
通常也就是這兩種時機會去作View層架構,基於這個時機的特殊性,咱們在這時候必須清楚認識到:View層的架構一旦實現或定型,在App發版後可修改的餘地就已經很是之小了。由於它跟業務關聯最爲緊密,因此哪怕稍微動一點點,它所引起的蝴蝶效應都不見得是業務方可以hold住的。這樣的狀況,就要求咱們在實現這個架構時,代碼必須得改得勤快,不能偷懶。也必須抱着充分的自我懷疑態度,作決策時要拿捏好尺度。git
View層的架構很是之重要,在我看來,這部分架構是這系列文章涉及4個方面最重要的一部分,沒有之一。爲何這麼說?程序員
View層架構是影響業務方迭代週期的因素之一github
產品經理產生需求的速度會很是快,尤爲是公司此時仍處於創業初期,在規模稍大的公司裏面,產品經理也喜歡挖大坑來在leader面前刷存在感,好比阿里。這就致使業務工程師任務很是繁重。正常狀況下讓產品經理砍需求是不太可能的,所以做爲架構師,在架構裏有一些可作可不作的事情,最好仍是能作就作掉,不要偷懶。這能夠幫業務方減負,編寫代碼的時候也能更加關注業務。web
我跟一些朋友交流的時候,他們都會或多或少地抱怨本身的團隊迭代速度不夠快,或者說,迭代速度不合理地慢。我認爲迭代速度不是想提就能提的,迭代速度的影響因素有不少,一期PRD裏的任務量和任務複雜度都會影響迭代週期能達到什麼樣的程度。拋開這些外在的不談,從內在可能致使迭代週期達不到合理的速度的緣由來看,其中有一個緣由頗有可能就是View層架構沒有作好,讓業務工程師完成一個不算複雜的需求時,須要處理太多額外的事情。固然,開會多,工程師水平爛也屬於迭代速度提不上去的內部緣由,但這個不屬於本文討論範圍。還有,加班不是優化迭代週期的正確方式
,嗯。面試
通常來講,一個不夠好的View層架構,主要緣由有如下五種:數據庫
- 代碼混亂不規範
- 過多繼承致使的複雜依賴關係
- 模塊化程度不夠高,組件粒度不夠細
- 橫向依賴
- 架構設計失去傳承
這五個地方會影響業務工程師實現需求的效率,進而拖慢迭代週期。View架構的其餘缺陷也會或多或少地產生影響,但在我看來這裏五個是比較重要的影響因素。若是你們以爲還有什麼因素比這四個更高的,能夠在評論區提出來我補上去。
對於第五點我想作一下強調:架構的設計是必定須要有傳承的,有傳承的架構從總體上看會很是協調。但實際狀況有多是一我的走了,另外一個頂上,即使任務交接得再完整,都不可避免不一樣的人有不一樣的架構思路,從而致使整個架構的流暢程度受到影響。要解決這個問題,一方面要儘可能避免單點問題,讓架構師作架構的時候再帶一我的。另外一方面,架構要設計得儘可能簡單,平緩接手人的學習曲線。我離開安居客的時候,作過保證:凡是從我手裏出來的代碼,終身保修
。因此不要想着離職了就什麼事兒都無論了,這不光是職業素養問題,還有一個是你對你的代碼是否足夠自信的問題。傳承性對於View層架構很是重要,由於它距離業務最近,改動餘地最小。
因此當各位CTO、技術總監、TeamLeader們以爲迭代週期不夠快時,你能夠先不忙着急吼吼地去招新人,《人月神話》早就說過加人不能徹底解決問題。這時候若是你能夠回過頭來看一下是否是View層架構不合理,把這個弄好也是優化迭代週期的手段之一。
嗯,至於本系列其餘三項的架構方案對於迭代週期的影響程度,我認爲都不如View層架構方案對迭代週期的影響高,因此這是我認爲View層架構是最重要的其中一個理由。
View層架構是最貼近業務的底層架構
View層架構雖然也算底層,但還沒那麼底層,它跟業務的對接面最廣,影響業務層代碼的程度也最深。在全部的底層都牽一髮的時候,在View架構上牽一髮致使業務層動全身的面積最大。
因此View架構在全部架構中一旦定型,可修改的空間就最小,咱們在一開始考慮View相關架構時,不光要實現功能,還要考慮更多規範上的東西。制定規範的目的一方面是防止業務工程師的代碼腐蝕View架構,另外一方面也是爲了可以有所傳承。按照規範來,總仍是不那麼容易出差池的。
還有就是,架構師一開始考慮的東西也會有不少,不可能在初版就把它們所有實現,對於一個還沒有發版的App來講,初版架構每每是最小完整功能集,那麼在第二版第三版的發展過程當中,架構的迭代任務就頗有可能不僅是你一我的的事情了,相信你一我的也不見得能搞定所有。因此你要跟你的合做者們有所約定。另外,初版出去以後,業務工程師在使用過程當中也會產生不少修改意見,哪些意見是合理的,哪些意見是不合理的,也要經過事先約定的規範來進行篩選,最終決定如何採納。
規範也不是一成不變的,何時槍斃意見,何時改規範,這就要靠各位的技術和經驗了。
以上就是前言。
這篇文章講什麼?
-
View代碼結構的規定
-
關於view的佈局
-
什麼時候使用storyboard,什麼時候使用nib,什麼時候使用代碼寫View
-
是否有必要讓業務方統一派生ViewController?
-
方便View佈局的小工具
-
MVC、MVVM、MVCS、VIPER
-
本門心法
-
跨業務時View的處理
-
留給評論區各類補
-
總結
View代碼結構的規定
架構師不是寫SDK出來交付業務方使用就沒事兒了的,每家公司必定都有一套代碼規範,架構師的職責也包括定義代碼規範。按照道理來說,定代碼規範應該是屬於通識,放在這裏講的緣由只是由於我這邊須要爲View添加一個規範。
制定代碼規範嚴格來說不屬於View層架構的事情,但它對View層架構將來的影響會比較大,也是屬於架構師在設計View層架構時須要考慮的事情。制定View層規範的重要性在於:
- 提升業務方View層的可讀性可維護性
- 防止業務代碼對架構產生腐蝕
- 確保傳承
- 保持架構發展的方向不輕易被不合理的意見所左右
在這一節裏面我不打算從頭開始定義一套規範,蘋果有一套Coding Guidelines,當咱們定代碼結構或規範的時候,首先必定要符合這個規範。
而後,相信你們各自公司裏面也都有一套本身的規範,具體怎麼個規範法其實也是根據各位架構師的經驗而定,我這邊只是建議各位在各自規範的基礎上再加上下面這一點。
viewController的代碼應該差很少是這樣:
要點以下:
全部的屬性都使用getter和setter
不要在viewDidLoad裏面初始化你的view而後再add,這樣代碼就很難看。在viewDidload裏面只作addSubview的事情,而後在viewWillAppear裏面作佈局的事情(勘誤1
),最後在viewDidAppear裏面作Notification的監聽之類的事情。至於屬性的初始化,則交給getter去作。
好比這樣:
#pragma mark - life cycle
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.firstTableView]; [self.view addSubview:self.secondTableView]; [self.view addSubview:self.firstFilterLabel]; [self.view addSubview:self.secondFilterLabel]; [self.view addSubview:self.cleanButton]; [self.view addSubview:self.originImageView]; [self.view addSubview:self.processedImageView]; [self.view addSubview:self.activityIndicator]; [self.view addSubview:self.takeImageButton]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CGFloat width = (self.view.width - 30) / 2.0f; self.originImageView.size = CGSizeMake(width, width); [self.originImageView topInContainer:70 shouldResize:NO]; [self.originImageView leftInContainer:10 shouldResize:NO]; self.processedImageView.size = CGSizeMake(width, width); [self.processedImageView right:10 FromView:self.originImageView]; [self.processedImageView topEqualToView:self.originImageView]; CGFloat labelWidth = self.view.width - 100; self.firstFilterLabel.size = CGSizeMake(labelWidth, 20); [self.firstFilterLabel leftInContainer:10 shouldResize:NO];