上週公眾號釋出的以下文章:
- Mac 命令列效率提升利器篇
- YYCache 原始碼解析(一):使用方法,架構與記憶體快取的設計
- 深入淺出 iOS 併發程式設計
- 單一職責原則在 iOS 中的應用
本期知識小集的主要內容包括:
- NSURLProtocol 的實際使用踩坑總結
- WKWebView 給 scrollView 新增 delegate crash
- 不需要接入 SDK 的三方登入及分享
instancetype
和id
的區別
NSURLProtocol 的實際使用踩坑總結
“使用 NSURLProtocol 攔截網路請求”相信很多人都有所耳聞,最近出於工作需要比較詳細地研究了一番,下面給出一些比較有用的踩坑總結。
1、需要明確:無論你有沒有用 NSURLProtocol 對 app 中的所有網路請求做統一處理,這些網路請求的發起者都應該是無感知的。舉個例子,在某個業務場景下,我使用自定義的 URLSession 發起網路請求,並實現各個代理方法來處理網路請求各個階段的事件。如果這個網路請求被 NSURLProtocol 攔截,仍然需要保證當初實現的各個代理方法都能被如期呼叫。為此,蘋果定義了 NSURLProtocolClient
協議,協議方法覆蓋了網路請求完整的生命週期。只要你在攔截之後重發的請求的各階段適時、完整地呼叫了協議中的方法,那麼最初的請求發起者便對“攔截”這件事毫無感知了,它的代理事件或者回撥的 block 都會在正確的時間被執行,無論這個請求最初是個 NSURLSessionDownloadTask
還是 NSURLConnection
。從這個角度來說,NSURLProtocol 是一個底層的攔截。
2、很多介紹 NSURLProtocol 的文章,會在每個 startLoading
方法的實現中,都建立 NSURLSession 例項,這是非常低效、失當的做法,具體原因其實和 NSURLProtocol 無關了,這是 NSURLSession 使用失當的問題。正確的實現應該是模擬 AFNetworking 的 SessionManager
,共享一個 session 例項,卻可以將歸屬於每一個 task 的回撥事件交由每一個 NSURLProtocol 例項處理,具體可以參考官方給出的 NSURLProtocol demo。或者,甚至可以直接使用 AFNetworking 來對攔截後的請求進行重發。
3、攔截重發一個 Request 之後,記得使用 setProperty:forKey:inRequest:
方法對該 Request 進行標記,防止進入死迴圈。
4、通過配置 Configuration
自定義的 Session 發出的請求,預設是無法被攔截到的,因為 NSURLSessionConfiguration
的屬性 protocolClasses
裡面,預設不包含我們自定義的 NSURLProtocol。這時,可以 hook protocolClasses 方法,加入我們自己的 protocol。
5、有的同學可能會糾結,最初的網路請求如果是一個 NSURLSessionDownloadTask
,它需要處理帶有已寫入資料、完整資料等資訊的回撥方法,而在 NSURLProtocol 中被攔截之後,統一採用 NSURLSessionDataTask 來重發,那當初的下載獨有的代理方法,還能被正確執行嗎?答案是肯定的,原因參考第一條。其實通過 NSURLProtocol 只提供了 NSURLRequest 來初始化的方法就可以看出來,在 NSURLProtocol 中,我們不需要關注最初的任務是何種 task,因為無論最初是什麼型別的 task,到 protocol 的初始化這裡時,你已經無法獲知它最初的 task 型別。
WKWebView 給 scrollView 新增 delegate crash
作者: Lefe_x
想監聽 WKWebView 的滾動,我的做法是設定 WKWebView.scrollView.delegate
,然而這種方法會導致在 iOS9 上 crash。使用全域性斷點並不能定位到 crash 的具體位置,當 crash 後,在列印控制檯處輸入 bt
,發現有輸出異常資訊,大體意思是 WKWebView 已經釋放,但在其它地方還在使用它的屬性 scrollView。
關於這個 crash 的描述:
Possible crash when setting the WKWebViews's scroll view delegate, if the scroll view outlives the web view
Null out the internal delegate on the WKScrollView when the WKWebView goes away, since it's possible for a client to set its own scroll view delegate, forcing the creation of a WKScrollViewDelegateForwarder, and then retain the UIScrollView past the lifetime of the WKWebView. In this situation, the WKScrollViewDelegateForwarder's internalDelegate would point to a deleted WKWebView.
想解決這個問題需要在,dealloc 的位置把 delegate 設定為 nil:
self.webView.scrollView.delegate = nil;
複製程式碼
參考:
- Webkit trac.webkit.org/changeset/1…
不需要接入 SDK 的三方登入及分享
**作者:**這個湯圓沒有餡
提到三方登入分享,第一反應大概是友盟、ShareSDK 之類。整合微信、QQ、微博三個平臺,友盟 SDK 大小 62.9M,ShareSDK 大小 74M,如果直接整合三個平臺的官方 SDK,分別大小如圖,則一共有 51M。
接入 SDK 後,在授權登入的回撥裡拿到各個平臺需要的值,再丟給後臺,由後臺去請求使用者資訊再與自己的使用者體系繫結。(當然每個人的方案可能不一樣,這只是其中一種) 如圖下圖,微信需要 code ,QQ 需要 openId 和 accessToken,微博需要 access_token。
這邊介紹一個叫 MonkeyKing
(github.com/nixzhu/Monk…) 的 Swift 庫,檔案大小隻有121KB,通過直接訪問url的方法拿到回撥。
先呼叫 MonkeyKing.registerAccount
註冊各個平臺,再如圖三呼叫授權登入的方法。
看了一下原始碼,實現原理如下:
- 微信:通過 weixin://app/YourAppId/auth/?scope=snsapi_userinfo&state=Weixinauth 拿到 code 值;
- QQ:通過 mqqOpensdkSSoLogin://SSoLogin/tencentXXX/com.tencent.tencentXXX?generalpastboard=1 拿到 openId 和 accessToken;
- 微博:是先設定剪下板引數,再通過 weibosdk://request?id=uuidString&sdkversion=003203000 獲取access_token;
MonkeyKing 除了登入功能外,還有分享及支付功能等。而這些功能的實現不需要整合任何 SDK,對 App 體積大小有要求的人來說,這個庫相當棒。
instancetype
和 id
的區別
作者: Vong_HUST
日常開發中,我們通常會複寫各種指定構造器或者自定義指定構造器,一般返回值都會寫成 instancetype,但是為什麼要寫 instancetype 而不是 id 呢?他們之間的區別在哪呢?
我們先來看下程式碼
@interface TestObjectA : NSObject
+ (id)createObjectA;
- (void)methodA;
@end
@interface TestObjectB : NSObject
+ (instancetype)createObjectB;
- (void)methodB;
@end
// 假設上面4個方法都有實現
[[TestObjectA createObjectA] methodB]; // 無編譯錯誤,但是崩潰
[[TestObjectB createObjectB] methodA]; // 編譯報錯:No visible @interface for 'TestObjectB' declares the selector 'methodA'
複製程式碼
從上圖可以看出,區別就在於:instancetype
能夠做到型別檢測而 id
不行。前者僅可做方法返回值,不能作為引數。但是可能會有人會有疑問,為什麼 - (id)initWithxxx:
也可以做到型別檢測呢?因為類方法只要以 alloc
、new
開頭就會有關聯返回型別(即型別檢測),例項方法只要以 init
、autorelease
、retain
、self
開頭就會有關聯返回型別。具體可以參考這篇文章
但是 ARC 下實測,例項方法只有 init
開頭的才有關聯返回型別。
關注我們
歡迎關注我們的公眾號:iOS-Tips,也歡迎加入我們的群組討論問題。可以公眾號留言 ios
、flutter
、web
、pwa
、小程式
等關鍵詞獲取入群方式。
目前 iOS 3號群
已到 300+,期待你的加入。