iOS界面跳轉(zhuǎn)以及一些優(yōu)化方案

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

iOS界面跳轉(zhuǎn)的一些優(yōu)化方案

App應(yīng)用程序開(kāi)發(fā), 界面跳轉(zhuǎn)是基礎(chǔ)中的基礎(chǔ), 幾乎沒(méi)有一個(gè)App是用不到界面跳轉(zhuǎn)的, 那么怎么樣去書(shū)寫(xiě)界面跳轉(zhuǎn)代碼才是比較合理的呢?

大家可能在想跳轉(zhuǎn)無(wú)非就2種方式, 能有什么內(nèi)容? 其實(shí)并不是這樣子的, 對(duì)于研發(fā)老手來(lái)說(shuō), 大型應(yīng)用幾乎都是利用URLScheme進(jìn)行全方位的解決方案; 對(duì)于研發(fā)新手來(lái)說(shuō), 他們可能并沒(méi)有遇到多路口界面跳轉(zhuǎn)的瓶頸, 只會(huì)使用一些常用跳轉(zhuǎn), 并不會(huì)意識(shí)到界面跳轉(zhuǎn)潛在的一些問(wèn)題, 甚至無(wú)法嚴(yán)格區(qū)分Present和Push的操作區(qū)別~

本文將針對(duì)界面跳轉(zhuǎn)提出一些優(yōu)化解決方案~

常用跳轉(zhuǎn)方式

iOS常用的跳轉(zhuǎn)方式只有兩種PresentPush。Push和Present最直觀的區(qū)別是默認(rèn)的轉(zhuǎn)場(chǎng)效果, Present的默認(rèn)轉(zhuǎn)場(chǎng)效果是自下而上的, Push的轉(zhuǎn)場(chǎng)效果是自右到左的汗洒。Push往往需要搭配UINavigationController來(lái)使用。

Push跳轉(zhuǎn)使用示意:

1

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

Present跳轉(zhuǎn)使用示意:

1

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

在大部分情況下, iOS研發(fā)者都在濫用Push的跳轉(zhuǎn)方式, 往往一個(gè)App僅僅包含一個(gè)UINavigationController。產(chǎn)生濫用的原因是因?yàn)镻resent的跳轉(zhuǎn)太過(guò)難于定制轉(zhuǎn)場(chǎng)效果, 僅僅只能使用系統(tǒng)提供的4種打開(kāi)方式。

在滿(mǎn)足產(chǎn)品要求的前提下, 其實(shí)可以基于模塊內(nèi)跳轉(zhuǎn)模塊外跳轉(zhuǎn)的思量去考慮采用Present的方式還是Push的方式去跳轉(zhuǎn)界面黎做。

PS: 還有一種界面切換方式是利用ChildViewController, 進(jìn)行獨(dú)立界面的控制敷硅。需要高度定制的界面可以采用這種方式, 例如基于地圖或者相機(jī)的應(yīng)用×螅基于ChildViewController的方式內(nèi)容篇幅太長(zhǎng), 在本文就暫時(shí)不介紹了, 以后再補(bǔ)充~

常用跳轉(zhuǎn)方式瓶頸

常用的跳轉(zhuǎn)方式其實(shí)已經(jīng)幾乎可以滿(mǎn)足我們所有的跳轉(zhuǎn), 但是欠缺一層業(yè)務(wù)層次的高層級(jí)封裝

舉一個(gè)實(shí)際使用場(chǎng)景, 某App支持4種頁(yè)面打開(kāi)方式:

Push推送

App外部網(wǎng)頁(yè)打開(kāi)

App內(nèi)部網(wǎng)頁(yè)打開(kāi)

應(yīng)用內(nèi)點(diǎn)擊打開(kāi)

這四種方式均跳轉(zhuǎn)到DetailViewController界面拳恋。普通的跳轉(zhuǎn)依然可以滿(mǎn)足該場(chǎng)景, 最簡(jiǎn)單的解決方案是在四個(gè)不同的地方都寫(xiě)一個(gè)獨(dú)立的界面打開(kāi)邏輯凡资。

作為一名業(yè)務(wù)模塊人才, 如此不復(fù)用代碼合理么? 作為一名App架構(gòu)師, 如此冗余四份入口代碼合適么?

如果您覺(jué)得不合適, 那自然需要去抽離代碼到統(tǒng)一的地方去書(shū)寫(xiě)一套統(tǒng)一的管理邏輯; 如果您覺(jué)得合適, 那么您會(huì)設(shè)想什么方案去根據(jù)外部網(wǎng)頁(yè)以及Push內(nèi)容去轉(zhuǎn)化代碼至普通跳轉(zhuǎn)代碼呢?

URLScheme解決方案

我們先根據(jù)前面提到的四種場(chǎng)景進(jìn)行場(chǎng)景分析:

外部網(wǎng)頁(yè)場(chǎng)景:

只能使用iOS自帶的URLScheme的方式去打開(kāi)App, 然后通過(guò)AppDelegate中事件去獲取對(duì)應(yīng)的URL進(jìn)行匹配

Push推送場(chǎng)景:

在extra字段中定義個(gè)鏈接字段, 鏈接字段是個(gè)字符串或者數(shù)字代號(hào), 用于在AppDelegate中事件去獲取對(duì)應(yīng)的代號(hào)進(jìn)行匹配; 既然代碼是自定義的, 那自然可以定義成一個(gè)URL了

內(nèi)部網(wǎng)頁(yè)場(chǎng)景

熟悉iOS WebView開(kāi)發(fā)的童鞋們都知道, UIWebView的JS交互本質(zhì)上是通過(guò)截獲URL請(qǐng)求去實(shí)現(xiàn)的, 那么既然是傳遞URL地址, 就可以和外部網(wǎng)頁(yè)使用相關(guān)的方式, 只不過(guò)在不同的位置進(jìn)行對(duì)應(yīng)的URL匹配

應(yīng)用內(nèi)點(diǎn)擊打開(kāi)

可以采用普通打開(kāi)方式, 也可以通過(guò)一個(gè)抽離的URLScheme匹配器去匹配打開(kāi)

根據(jù)上述四個(gè)場(chǎng)景, 我們可以發(fā)現(xiàn), 解決上述四個(gè)應(yīng)用場(chǎng)景, 我們需要的是引入一個(gè)抽離的URLScheme匹配器去匹配打開(kāi)輪轉(zhuǎn)界面~

利用URLScheme的方式進(jìn)行一層封裝, 幾乎可以完美解決多入口打開(kāi)App的邏輯復(fù)用問(wèn)題。

PS: 一般情況下, URLScheme的抽離器不需要自己封裝, 可以使用開(kāi)源現(xiàn)成的, 很少場(chǎng)景需要高度定制。

開(kāi)源URLScheme解決方案:

RoutableAndroid和iOS均支持的一款權(quán)威的應(yīng)用內(nèi)URL跳轉(zhuǎn)路由, 幾乎可以滿(mǎn)足所有需求

代碼切入性比較低, 沒(méi)有冗余的繼承封裝隙赁。

可以指定NavigationController, 方便定制ChildController的跳轉(zhuǎn)

可以多個(gè)Router組合使用, 靈活性高

urlmananger國(guó)內(nèi)技術(shù)問(wèn)題網(wǎng)站segmentfault.com開(kāi)發(fā)者抽離的一個(gè)跳轉(zhuǎn)器

需要嵌入繼承和綁定使用NavigationController, 架構(gòu)設(shè)計(jì)層級(jí)嵌入性很高, 沒(méi)有Routable合理

無(wú)法多個(gè)組合使用, 靈活性沒(méi)有Routable高

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

個(gè)人比較傾向使用Routable, 因?yàn)椴](méi)有在架構(gòu)上對(duì)代碼進(jìn)行嵌入, 比較符合開(kāi)發(fā)者口味~

以Routable作為示例, 本文可以通過(guò)如下代碼在App啟動(dòng)的時(shí)候就提前注冊(cè)(PS: Push點(diǎn)擊打開(kāi)執(zhí)行Optional參數(shù)之前注冊(cè))

1

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

假設(shè)您的App URLScheme前綴為demo123, 您只需要在上述四個(gè)場(chǎng)景分別傳遞demo123://detail/88過(guò)來(lái)即可垦藏。88只是示例的一個(gè)隨意亂寫(xiě)的id編號(hào), 作為Restful分格的參數(shù)進(jìn)行處理。

URLScheme些許問(wèn)題

URLScheme進(jìn)行界面跳轉(zhuǎn)的解決方案也不是完美的, 個(gè)人開(kāi)發(fā)時(shí)候遇到最大的問(wèn)題就是傳值問(wèn)題

怎么傳遞對(duì)象值

URLScheme原則上不支持傳遞復(fù)雜的對(duì)象, 通過(guò)URLScheme方式打開(kāi)的界面理論上每個(gè)界面都相對(duì)保持邏輯獨(dú)立(邏輯獨(dú)立的代價(jià)往往是犧牲細(xì)微的用戶(hù)體驗(yàn)), 邏輯獨(dú)立的界面可以有更好的架構(gòu)設(shè)計(jì)

通過(guò)外部URL或者Push的方式是無(wú)法傳遞對(duì)象的, 可以不用考慮傳遞對(duì)象的場(chǎng)景

應(yīng)用內(nèi)界面跳轉(zhuǎn)可以根據(jù)實(shí)際場(chǎng)景去區(qū)分使用URLScheme的方式還是普通的方式進(jìn)行界面跳轉(zhuǎn)控制

怎么傳遞URL值

URLScheme打開(kāi)的界面有時(shí)候也需要傳遞URL值用于對(duì)應(yīng)的界面, 最常見(jiàn)的是打開(kāi)圖片管理器以及打開(kāi)WebView的界面, 這種場(chǎng)景可以采用約定加密的方式進(jìn)行處理, 對(duì)傳遞的URL進(jìn)行URIEncode和取值時(shí)候的URIDecode伞访。

Push長(zhǎng)度限制

坑爹的APNs規(guī)定了Push內(nèi)容的總長(zhǎng)度不能大于255字節(jié), 那么URLScheme的參數(shù)傳遞就收到限制掂骏。

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

還有一種通過(guò)的Push長(zhǎng)度解決方案是, push只是觸發(fā)器, 觸發(fā)App請(qǐng)求去獲取真正的內(nèi)容來(lái)繞過(guò)長(zhǎng)度限制厚掷。

傳值對(duì)象

此處針對(duì)應(yīng)用內(nèi)跳轉(zhuǎn)使用url scheme還是普通方式進(jìn)行一些議論, 個(gè)人覺(jué)得一套應(yīng)用里如果有兩種方式跳轉(zhuǎn), 雖然靈活性高, 但是比較難以控制, 因此最好都采用一套方式跳轉(zhuǎn), 那自然是使用url scheme弟灼。那復(fù)雜傳值的問(wèn)題依舊無(wú)法得到解決。

有些開(kāi)發(fā)者為了省時(shí)間, 直接通過(guò)類(lèi)似Notification的方式或者用單例對(duì)象去維護(hù)進(jìn)行值傳遞, 也不失為一個(gè)方法冒黑。

但是我在思考, 有沒(méi)有一種相對(duì)完美的解決方案, 能夠?qū)髦祮?wèn)題徹底用url scheme進(jìn)行傳遞呢?

結(jié)合本人喜歡使用的庫(kù)JSONModel, 我想到了一種暴力且耗時(shí)的解決方案, 但是至少不產(chǎn)生耦合哈~

暴力解決方案步驟:

JSON化對(duì)象

將對(duì)象JSON字符串Base64加密

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

接受者處理參數(shù)的時(shí)候反Base64解密

將解密后的JSON對(duì)象用模型實(shí)例化

針對(duì)暴力解決方案, 本人設(shè)想了四個(gè)自問(wèn)自答:

為什么不直接Base64對(duì)象而需要將其JSON字符串話(huà)呢?

答: 為了接受者解密后的直觀性田绑。在大型App開(kāi)發(fā)過(guò)程中, 解密者解析后不一定知道用哪個(gè)模型去實(shí)例化JSON字符串, 通過(guò)這種方式, 解密者可以不關(guān)心接受數(shù)據(jù)后的模型實(shí)例而自由發(fā)揮。

利用這種方式暴力解決后, url會(huì)不會(huì)很長(zhǎng)?

答: 這種方式傳遞的url會(huì)超級(jí)長(zhǎng), 但是在應(yīng)用內(nèi)進(jìn)行頁(yè)面處理的場(chǎng)景, 不需要可以的去考慮url的長(zhǎng)度抡爹。但是url的長(zhǎng)度可能會(huì)影響解析的性能掩驱。

為什么不直接通過(guò)廣播或者單例維護(hù)的方式傳值?

答: 為了解耦。 大型App維護(hù)的時(shí)候, 如果一個(gè)內(nèi)存對(duì)象是公用的, 是十分難以維護(hù)的, 應(yīng)該盡量減少傳遞對(duì)象之間的耦合豁延。

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

答: 為了解決模型嵌套的問(wèn)題昙篙。因?yàn)橐粋€(gè)模型里可能會(huì)嵌套另外一個(gè)模型, 當(dāng)然通過(guò)JSON字符串本身可以實(shí)現(xiàn)模型嵌套的解決, 那可以有更加節(jié)省性能的解決方案。

本人水平有限, 此處的暴力的方式是目前本人覺(jué)得相對(duì)耦合度低并且比較好的一種解決方案诱咏。對(duì)于目前的iOS手機(jī)設(shè)備來(lái)說(shuō), 這點(diǎn)JSON以及解密的性能并不能影響整個(gè)App的運(yùn)行, 因此采用這種方式進(jìn)行暴力解決苔可。

總結(jié)

頁(yè)面輪轉(zhuǎn)在小型的App并不需要針對(duì)單獨(dú)進(jìn)行優(yōu)化設(shè)計(jì), 但是對(duì)于上20w行代碼的大型App來(lái)說(shuō), 往往都是需要針對(duì)優(yōu)化的。

本文引用了市面上最通用的URLScheme的解決方案來(lái)進(jìn)行頁(yè)面跳轉(zhuǎn)的設(shè)計(jì)優(yōu)化, 并建議采用開(kāi)源庫(kù)Routable來(lái)進(jìn)行統(tǒng)一管理袋狞。

根據(jù)個(gè)人在界面跳轉(zhuǎn)開(kāi)發(fā)中遇到的困難, 提出了幾個(gè)相應(yīng)的瓶頸和對(duì)應(yīng)的解決方案焚辅。針對(duì)傳遞對(duì)象值提出了一種暴力但是耦合度比較低的解決方案。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苟鸯,一起剝皮案震驚了整個(gè)濱河市同蜻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌早处,老刑警劉巖湾蔓,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異砌梆,居然都是意外死亡默责,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)咸包,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)桃序,“玉大人,你說(shuō)我怎么就攤上這事烂瘫∶叫埽” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芦鳍。 經(jīng)常有香客問(wèn)我嚷往,道長(zhǎng),這世上最難降的妖魔是什么怜校? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任间影,我火速辦了婚禮,結(jié)果婚禮上茄茁,老公的妹妹穿的比我還像新娘。我一直安慰自己巩割,他們只是感情好裙顽,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著宣谈,像睡著了一般愈犹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闻丑,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天漩怎,我揣著相機(jī)與錄音,去河邊找鬼嗦嗡。 笑死勋锤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的侥祭。 我是一名探鬼主播叁执,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼矮冬!你這毒婦竟也來(lái)了谈宛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胎署,失蹤者是張志新(化名)和其女友劉穎吆录,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體琼牧,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恢筝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了障陶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滋恬。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抱究,靈堂內(nèi)的尸體忽然破棺而出恢氯,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布勋拟,位于F島的核電站勋磕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敢靡。R本人自食惡果不足惜挂滓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啸胧。 院中可真熱鬧赶站,春花似錦、人聲如沸纺念。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)陷谱。三九已至烙博,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烟逊,已是汗流浹背渣窜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宪躯,地道東北人乔宿。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像眷唉,于是被迫代替她去往敵國(guó)和親予颤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,276評(píng)論 25 707
  • 前言: 本文轉(zhuǎn)自前同事casa的博文冬阳,這篇文章是基于runtime實(shí)現(xiàn)的iOS組件化方案蛤虐,其實(shí)iOS組件化方案基本...
    monkey01閱讀 1,667評(píng)論 1 2
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件肝陪、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,118評(píng)論 4 61
  • iOS應(yīng)用架構(gòu)談 組件化方案 討論論壇 源 簡(jiǎn)述 前幾天的一個(gè)晚上在infoQ的微信群里驳庭,來(lái)自蘑菇街的Limboy...
    其實(shí)也沒(méi)有閱讀 1,431評(píng)論 1 9
  • iOS即時(shí)通訊,從入門(mén)到“放棄”氯窍?socket的半包饲常,粘包與分包的問(wèn)題iOS 處理socket粘包問(wèn)題iOS___...
    xiari1991閱讀 106評(píng)論 0 0