面试题记录

WKWebView 坑

  1. 白屏 WebContentProcessDidTerminate 回调中处理 或监听 title
  2. cookie
  3. 清除缓存
  4. https (plist)

多个 WKWebView 共享缓存

  1. 核心使用 WKProcessPool 实现一个单例,之后的多个 WKWebviewConfiguration 共享这个单例。
  2. 办法一:添加 WKUserContentController WKProcessPool 实例,之后使用 WKUserScript 来添加需要共享数据的方法
  3. 办法二:自己实现一个缓存管理器,使用 decidePolicyFor navigationActiondecidePolicyFor navigationResponse 来截获请求响应之前和响应之后的回调,分别用于添加缓存和获取缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
let userContentController = WKUserContentController.init()
let config = WKWebViewConfiguration.init()
config.userContentController = userContentController
let processPool = WKProcessPool.init()
config.processPool = processPool
let cookieScript = WKUserScript.init(source: self.getCookie(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
userContentController.addUserScript(cookieScript)

func getCookie() -> String {
    let cookie = UserDefaults.get(json: "gacfcavlearning")
    var str = ""
    for key in cookie.dictionaryValue.keys {
        let value = cookie.dictionaryValue[key]?.stringValue
        if value != nil {
            str += "\(key)=\(value!)"
        }
    }
    return "document.cookie='\(str)';"
}

func reloadWithCookie(request: URLRequest) {
    var req = request

    let cookie = UserDefaults.get(json: "gacfcavlearning")
    var str = ""
    for key in cookie.dictionaryValue.keys {
        let value = cookie.dictionaryValue[key]?.stringValue
        if value != nil {
            str += "\(key)=\(value!);"
        }
    }

    req.addValue(str, forHTTPHeaderField: "Cookie")
    self.webView.load(req)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if navigationAction.request.url?.absoluteString.contains("gacfcavlearning") ?? false {
        if let headers = navigationAction.request.allHTTPHeaderFields {
            if headers["Cookie"] == nil && UserDefaults.get(json: "gacfcavlearning").dictionaryValue.keys.count > 0 {
                decisionHandler(.cancel)
                self.reloadWithCookie(request: navigationAction.request)
                return
            } else {
                decisionHandler(.allow)
                return
            }
        }
    }
    decisionHandler(.allow)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    if #available(iOS 11.0, *) {
        let store: WKHTTPCookieStore = webView.configuration.websiteDataStore.httpCookieStore
        var dic: [String : String] = [:]
        store.getAllCookies { (cookies) in
            for c in cookies {
                if c.domain.contains("gacfcavlearning") {
                    debugPrint(c)
                    dic[c.name] = c.value
                }
            }
            if dic.keys.count != 0 {
                UserDefaults.set(key: "gacfcavlearning", json: JSON.init(dic))
                debugPrint("最终的字典 = \(dic)")
            }
        }
    } else {
        let resp = navigationResponse.response as! HTTPURLResponse
        let cookie = HTTPCookie.cookies(withResponseHeaderFields: resp.allHeaderFields as! [String : String], for: navigationResponse.response.url!)
        debugPrint(cookie)
    }
    decisionHandler(.allow)
}

WKWebView开启缓存和清除缓存

  1. 缓存使用 URLRequestURLRequest.CachePolicy
  2. 清除缓存
// 如果这个也不行 可以直接把本地目录中的文件删了 /Library/Caches/WebKit/NetworkCache
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{

}];

Swift 实现可选协议的方式,如何提供默认实现

  1. optional
  2. 使用 Extension 实现

单线程如何实现异步

js/dart 虽然是单线程,但宿主环境(手机,浏览器)确是多线程的,实现异步的方式主要是靠一个叫做 事件循环机制 的东西。

异步的实现大概是这样:

js class 的本质是什么,如何实现继承

class 的本质是 function https://www.cnblogs.com/yangdaren/p/10759868.html https://blog.csdn.net/It_sharp/article/details/87360386

flutter 如何实现并发

使用 isolate https://www.jianshu.com/p/0aefa62372c6 注意:Future.value('str1').then(() => debugPrint('str'2))这种情况是 str2 先输出

flutter context 的本质是什么

https://www.jianshu.com/p/509b77b26b78

atomic 一定是线程安全的吗,为什么

不一定 (主要是setter加锁) 不安全的地方 :https://stackoverflow.com/questions/12347236/which-is-threadsafe-atomic-or-non-atomic 锁一个对象 里面对他进行赋值操作会导致锁无效 http://mrpeak.cn/blog/synchronized/

atomic 的系统实现是什么,自旋锁和互斥锁,自旋锁的风险,如果用自旋锁锁住一个nil会发生什么

10以后是互斥锁 10以前是自旋锁 互斥锁和自旋锁的区别:互斥锁,在等待获得锁的时候线程会休眠,而自旋锁是一直不断尝试去获取锁。

所以优缺点在于:互斥锁需要cpu的线程调度,如果短时间内就能获得锁则不是很划算,更适合长时间等待。自旋锁则适合短时间内获得锁,如果不能获得会一直消耗cpu

kvo 的是如何实现的

两步 第一步动态创建被监听的子类改变被监听属性的setter方法。第二步,使用isa指针混写,把原对象的isa指针指向新的类,就可以观察到setter前后的变化