iOS界面跳轉以及一些優化方案

原文地址: http://blog.startry.com/2016/02/14/Think-Of-UIViewController-Switch/

iOS界面跳轉的一些優化方案

App應用程序開發, 界面跳轉是基礎中的基礎, 幾乎沒有一個App是用不到界面跳轉的, 那么怎么樣去書寫界面跳轉代碼才是比較合理的呢?

大家可能在想跳轉無非就2種方式, 能有什么內容? 其實并不是這樣子的, 對于研發老手來說, 大型應用幾乎都是利用URLScheme進行全方位的解決方案; 對于研發新手來說, 他們可能并沒有遇到多路口界面跳轉的瓶頸, 只會使用一些常用跳轉, 并不會意識到界面跳轉潛在的一些問題, 甚至無法嚴格區分Present和Push的操作區別~

本文將針對界面跳轉提出一些優化解決方案~

常用跳轉方式

iOS常用的跳轉方式只有兩種PresentPush。Push和Present最直觀的區別是默認的轉場效果, Present的默認轉場效果是自下而上的, Push的轉場效果是自右到左的。Push往往需要搭配UINavigationController來使用。

Push跳轉使用示意:

1

UIViewController *nextViewController = [[UIViewController alloc] init];nextViewController.title = @"第二個界面";[self.navigationController pushViewController:nextViewController animated:YES];

Present跳轉使用示意:

1

UIViewController *nextViewController = [[UIViewController alloc] init];nextViewController.title = @"第二個界面";[self presentViewController:nextViewContrller animated:YES completed:nil];

在大部分情況下, iOS研發者都在濫用Push的跳轉方式, 往往一個App僅僅包含一個UINavigationController。產生濫用的原因是因為Present的跳轉太過難于定制轉場效果, 僅僅只能使用系統提供的4種打開方式。

在滿足產品要求的前提下, 其實可以基于模塊內跳轉模塊外跳轉的思量去考慮采用Present的方式還是Push的方式去跳轉界面。

PS: 還有一種界面切換方式是利用ChildViewController, 進行獨立界面的控制。需要高度定制的界面可以采用這種方式, 例如基于地圖或者相機的應用。基于ChildViewController的方式內容篇幅太長, 在本文就暫時不介紹了, 以后再補充~

常用跳轉方式瓶頸

常用的跳轉方式其實已經幾乎可以滿足我們所有的跳轉, 但是欠缺一層業務層次的高層級封裝

舉一個實際使用場景, 某App支持4種頁面打開方式:

Push推送

App外部網頁打開

App內部網頁打開

應用內點擊打開

這四種方式均跳轉到DetailViewController界面。普通的跳轉依然可以滿足該場景, 最簡單的解決方案是在四個不同的地方都寫一個獨立的界面打開邏輯。

作為一名業務模塊人才, 如此不復用代碼合理么? 作為一名App架構師, 如此冗余四份入口代碼合適么?

如果您覺得不合適, 那自然需要去抽離代碼到統一的地方去書寫一套統一的管理邏輯; 如果您覺得合適, 那么您會設想什么方案去根據外部網頁以及Push內容去轉化代碼至普通跳轉代碼呢?

URLScheme解決方案

我們先根據前面提到的四種場景進行場景分析:

外部網頁場景:

只能使用iOS自帶的URLScheme的方式去打開App, 然后通過AppDelegate中事件去獲取對應的URL進行匹配

Push推送場景:

在extra字段中定義個鏈接字段, 鏈接字段是個字符串或者數字代號, 用于在AppDelegate中事件去獲取對應的代號進行匹配; 既然代碼是自定義的, 那自然可以定義成一個URL了

內部網頁場景

熟悉iOS WebView開發的童鞋們都知道, UIWebView的JS交互本質上是通過截獲URL請求去實現的, 那么既然是傳遞URL地址, 就可以和外部網頁使用相關的方式, 只不過在不同的位置進行對應的URL匹配

應用內點擊打開

可以采用普通打開方式, 也可以通過一個抽離的URLScheme匹配器去匹配打開

根據上述四個場景, 我們可以發現, 解決上述四個應用場景, 我們需要的是引入一個抽離的URLScheme匹配器去匹配打開輪轉界面~

利用URLScheme的方式進行一層封裝, 幾乎可以完美解決多入口打開App的邏輯復用問題。

PS: 一般情況下, URLScheme的抽離器不需要自己封裝, 可以使用開源現成的, 很少場景需要高度定制。

開源URLScheme解決方案:

RoutableAndroid和iOS均支持的一款權威的應用內URL跳轉路由, 幾乎可以滿足所有需求

代碼切入性比較低, 沒有冗余的繼承封裝。

可以指定NavigationController, 方便定制ChildController的跳轉

可以多個Router組合使用, 靈活性高

urlmananger國內技術問題網站segmentfault.com開發者抽離的一個跳轉器

需要嵌入繼承和綁定使用NavigationController, 架構設計層級嵌入性很高, 沒有Routable合理

無法多個組合使用, 靈活性沒有Routable高

封裝層次高, 快速使用可以采用

個人比較傾向使用Routable, 因為并沒有在架構上對代碼進行嵌入, 比較符合開發者口味~

以Routable作為示例, 本文可以通過如下代碼在App啟動的時候就提前注冊(PS: Push點擊打開執行Optional參數之前注冊)

1

[[Routable sharedRouter] map:@"detail/:id" toController:[DetailController class]];

假設您的App URLScheme前綴為demo123, 您只需要在上述四個場景分別傳遞demo123://detail/88過來即可。88只是示例的一個隨意亂寫的id編號, 作為Restful分格的參數進行處理。

URLScheme些許問題

URLScheme進行界面跳轉的解決方案也不是完美的, 個人開發時候遇到最大的問題就是傳值問題

怎么傳遞對象值

URLScheme原則上不支持傳遞復雜的對象, 通過URLScheme方式打開的界面理論上每個界面都相對保持邏輯獨立(邏輯獨立的代價往往是犧牲細微的用戶體驗), 邏輯獨立的界面可以有更好的架構設計

通過外部URL或者Push的方式是無法傳遞對象的, 可以不用考慮傳遞對象的場景

應用內界面跳轉可以根據實際場景去區分使用URLScheme的方式還是普通的方式進行界面跳轉控制

怎么傳遞URL值

URLScheme打開的界面有時候也需要傳遞URL值用于對應的界面, 最常見的是打開圖片管理器以及打開WebView的界面, 這種場景可以采用約定加密的方式進行處理, 對傳遞的URL進行URIEncode和取值時候的URIDecode。

Push長度限制

坑爹的APNs規定了Push內容的總長度不能大于255字節, 那么URLScheme的參數傳遞就收到限制。

最常用的解決方案是壓縮字段名字和內容, 傳遞的字段勁量用一個單詞表示, 值字段可以隱藏掉URLScheme的前綴, 只保留后綴以及參數。

還有一種通過的Push長度解決方案是, push只是觸發器, 觸發App請求去獲取真正的內容來繞過長度限制。

傳值對象

此處針對應用內跳轉使用url scheme還是普通方式進行一些議論, 個人覺得一套應用里如果有兩種方式跳轉, 雖然靈活性高, 但是比較難以控制, 因此最好都采用一套方式跳轉, 那自然是使用url scheme。那復雜傳值的問題依舊無法得到解決。

有些開發者為了省時間, 直接通過類似Notification的方式或者用單例對象去維護進行值傳遞, 也不失為一個方法。

但是我在思考, 有沒有一種相對完美的解決方案, 能夠將傳值問題徹底用url scheme進行傳遞呢?

結合本人喜歡使用的庫JSONModel, 我想到了一種暴力且耗時的解決方案, 但是至少不產生耦合哈~

暴力解決方案步驟:

JSON化對象

將對象JSON字符串Base64加密

將Base64加密后的字符串作為url參數傳遞

接受者處理參數的時候反Base64解密

將解密后的JSON對象用模型實例化

針對暴力解決方案, 本人設想了四個自問自答:

為什么不直接Base64對象而需要將其JSON字符串話呢?

答: 為了接受者解密后的直觀性。在大型App開發過程中, 解密者解析后不一定知道用哪個模型去實例化JSON字符串, 通過這種方式, 解密者可以不關心接受數據后的模型實例而自由發揮。

利用這種方式暴力解決后, url會不會很長?

答: 這種方式傳遞的url會超級長, 但是在應用內進行頁面處理的場景, 不需要可以的去考慮url的長度。但是url的長度可能會影響解析的性能。

為什么不直接通過廣播或者單例維護的方式傳值?

答: 為了解耦。 大型App維護的時候, 如果一個內存對象是公用的, 是十分難以維護的, 應該盡量減少傳遞對象之間的耦合。

為什么需要base64加密而不直接采用uriencode的方式?

答: 為了解決模型嵌套的問題。因為一個模型里可能會嵌套另外一個模型, 當然通過JSON字符串本身可以實現模型嵌套的解決, 那可以有更加節省性能的解決方案。

本人水平有限, 此處的暴力的方式是目前本人覺得相對耦合度低并且比較好的一種解決方案。對于目前的iOS手機設備來說, 這點JSON以及解密的性能并不能影響整個App的運行, 因此采用這種方式進行暴力解決。

總結

頁面輪轉在小型的App并不需要針對單獨進行優化設計, 但是對于上20w行代碼的大型App來說, 往往都是需要針對優化的。

本文引用了市面上最通用的URLScheme的解決方案來進行頁面跳轉的設計優化, 并建議采用開源庫Routable來進行統一管理。

根據個人在界面跳轉開發中遇到的困難, 提出了幾個相應的瓶頸和對應的解決方案。針對傳遞對象值提出了一種暴力但是耦合度比較低的解決方案。

PS: 本人水平有限, 有錯誤的地方還望大家及時指出~ 謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,590評論 25 707
  • 前言: 本文轉自前同事casa的博文,這篇文章是基于runtime實現的iOS組件化方案,其實iOS組件化方案基本...
    monkey01閱讀 1,674評論 1 2
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,147評論 4 61
  • iOS應用架構談 組件化方案 討論論壇 源 簡述 前幾天的一個晚上在infoQ的微信群里,來自蘑菇街的Limboy...
    其實也沒有閱讀 1,439評論 1 9
  • iOS即時通訊,從入門到“放棄”?socket的半包,粘包與分包的問題iOS 處理socket粘包問題iOS___...
    xiari1991閱讀 106評論 0 0