眾所周知,在面試的時候Runtime、數(shù)據(jù)結(jié)構(gòu)等等都是面試常問的題目部脚,當(dāng)然,不少朋友會吐槽面試問題常常脫離實(shí)際開發(fā)裤纹,畢竟那些只有一兩人兩三人組成的小開發(fā)組的項(xiàng)目委刘,整個項(xiàng)目往往只有一兩次使用到Runtime的機(jī)會丧没,甚至有的項(xiàng)目根本就是從頭到尾都沒用到過。
當(dāng)然嘛锡移,就算沒用到過呕童,但這方面的知識儲備還是需要的,不然面試根本就沒啥問題好問淆珊,全都是UI層次夺饲、業(yè)務(wù)邏輯的問題,別說面試官施符,面試者都可能會覺得蛋疼的緊吧往声?
話題扯遠(yuǎn)了,言歸正傳戳吝,Runtime還有使用到的機(jī)會浩销,那么鏈表這一概念在移動端開發(fā)到底會在什么時候被應(yīng)用到呢?在廁所中沉思的時候我突然想到這個問題听哭,移動端開發(fā)到底有什么功能開發(fā)會使用到鏈表的概念慢洋,非鏈表不能,又或者是使用鏈表會達(dá)到最好效果的呢陆盘?
身體放空的同時心靈也得到了升華普筹,我終于想到了一個可能性,那就是Web的歷史追溯礁遣。
在PC使用谷歌瀏覽器的時候在一次偶然的巧合下我發(fā)現(xiàn)了谷歌瀏覽器讓人眼前一亮的功能斑芜,具體模擬使用場景是這樣的:
1、松鼠癥的我堆積了大量的標(biāo)簽頁祟霍,其中一些標(biāo)簽頁是有下一級的Web鏈接及上一級的Web鏈接
2杏头、不小心錯誤關(guān)閉了其中一個標(biāo)簽頁,那個標(biāo)簽頁是我找了很久的資料沸呐,標(biāo)簽頁的前進(jìn)跟后退都是同一個網(wǎng)站的重要資料
3醇王、通過谷歌瀏覽器的打開最近關(guān)閉的標(biāo)簽頁我重新打開了標(biāo)簽頁,并且崭添,上一級的Web鏈接以及下一級的Web鏈接依然存在寓娩。
這是很棒的功能,讓人眼前一亮呼渣,而遺憾的是手機(jī)上的瀏覽器大多沒有這樣的功能(至少我日常使用的都沒見到)棘伴,那么作為一個開發(fā)者,我們要如何將這樣的功能挪移到手機(jī)上呢屁置?
我想到了鏈表焊夸,Web一級一級的連接方式無疑是鏈表的最佳詮釋,當(dāng)頁面被關(guān)閉時將完成的鏈表保存下來蓝角,當(dāng)頁面被從新打開時從鏈表讀取數(shù)據(jù)似乎是很好的解決辦法阱穗。
為了佐證我的想法饭冬,首先先寫一個Web Demo.
let web = WKWebView(frame: CGRect.zero)
web.navigationDelegate = self
view.addSubview(web)
class ViewController: UIViewController,WKNavigationDelegate {
......
//實(shí)現(xiàn)代理方法來獲取URL地址,亦可通過監(jiān)聽Loading狀態(tài)揪阶,這些都隨便昌抠,需要注意的是,度娘會做相關(guān)網(wǎng)址轉(zhuǎn)譯鲁僚,這些轉(zhuǎn)譯需要根據(jù)自己選是否篩選炊苫。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
print(navigationAction.request.url?.absoluteString)
decisionHandler(WKNavigationActionPolicy.allow)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
print(navigationResponse.response.url)
decisionHandler(WKNavigationResponsePolicy.allow)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print(webView.url)
}
public class ListNode {
//商業(yè)項(xiàng)目中我們不應(yīng)該直接添加URLString,而是一個完整的數(shù)據(jù)模型冰沙,不過在此劝评,我們簡化一些操作。
public var url: String
public var next: ListNode?
public init(_ url: String) {
self.url = url
self.next = nil
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let node = ListNode(webView.url!.absoluteString )
if let l = list {
node.next = l
list = node
} else {
list = node
}
}
如此倦淀,我們便獲得了一個完整的鏈表蒋畜,里面記錄了標(biāo)簽頁從新建之始記錄的所有URL地址,并且撞叽,這是從尾到頭的姻成,若想要進(jìn)行歷史回溯便一層一層地將list.next中的url數(shù)據(jù)取出即可。
func goBack() {
let urlString = list?.next?.url ?? ""
list = list?.next
let request = URLRequest(url: URL(string: urlString)!)
web?.load(request)
}
但是這樣在實(shí)際使用上是會出很大問題的愿棋,首先是每次歷史回溯都將數(shù)據(jù)替代了科展,要是想回到原先的界面就只能使用WebView的goBack API,原本是最尾末的頁面但因?yàn)殛P(guān)閉而重新打開卻成了最初始的,這樣很容易造成業(yè)務(wù)邏輯上的混亂糠雨。
其二才睹,如果是同時具有上一級以及下一級URL(即不處于鏈表的首末尾)的Web,這樣的邏輯并不能使得Web goForward,功能并沒有完全實(shí)現(xiàn)甘邀。
除此之外還有等等問題在實(shí)際項(xiàng)目會有很多不同之處琅攘,需要一一調(diào)整。
在此松邪,我認(rèn)為可以這么設(shè)計(jì)坞琴,一個鏈表不夠就再加一個,兩個鏈表分別代表當(dāng)前頁面之前的數(shù)據(jù)以及這個頁面之后的數(shù)據(jù)逗抑,當(dāng)前頁面可以選擇性地放在兩個鏈表的首末剧辐。
//當(dāng)頁面處于正常狀態(tài)而非是被打開的最近關(guān)閉標(biāo)簽頁時按正常流程走
//當(dāng)頁面處于正常狀態(tài)而調(diào)用webView的goBack API 及 goForward API時改動雙鏈表
//當(dāng)調(diào)用goBack API 時,將goBack之前的頁面從before List刪除邮府,添加到 after List荧关,并成為after List的 First Node.
//當(dāng)調(diào)用goForward API 時,逆轉(zhuǎn)而使
//如此褂傀,確保雙鏈表模擬的完整鏈表的正確性以及當(dāng)前頁面的url在完整鏈表中位置的正確性
//當(dāng)頁面是最近被關(guān)閉的標(biāo)簽頁時檢查頁面的雙鏈表忍啤,確定頁面的url在鏈表中的位置
//根據(jù)鏈表是否有值判斷當(dāng)前頁面是否存在上一級的頁面或者下一級的頁面
//同樣的,根據(jù)調(diào)用的API對雙鏈表做出修正紊服。
......
//雙鏈表
var before:ListNode? //當(dāng)前網(wǎng)頁之前的鏈表數(shù)據(jù),當(dāng)前網(wǎng)頁處于鏈表頭部
var after:ListNode? //當(dāng)前網(wǎng)頁之后的鏈表數(shù)據(jù)
//監(jiān)聽按鈕點(diǎn)擊以挪移鏈表
@IBAction func goBack(_ sender: AnyObject) {
if web!.canGoBack {
if let b = before {
let node = b
before = b.next
if let a = after {
node.next = a
}
after = node
}
} else {
}
}
@IBAction func goForward(_ sender: AnyObject) {
if web!.canGoForward {
if let a = after {
let node = a
after = a.next
if let b = before {
node.next = b
}
before = node
}
} else {
}
}
如此在正常狀態(tài)不斷挪移鏈表檀轨,在最近關(guān)閉的標(biāo)簽頁中獲取數(shù)據(jù)時方能獲取到正確數(shù)據(jù)。
目前正在寫一個完整的Web項(xiàng)目以正確模擬商業(yè)項(xiàng)目如此使用可能會出現(xiàn)的問題欺嗤,所以本文僅是探討如此的功能實(shí)現(xiàn)参萄,不能避免邏輯上可能存在的問題。