原文連接html
上週公衆號發佈的如下文章:ios
本期知識小集的主要內容包括:git
instancetype
和 id
的區別「使用 NSURLProtocol 攔截網絡請求」相信不少人都有所耳聞,最近出於工做須要比較詳細地研究了一番,下面給出一些比較有用的踩坑總結。github
一、須要明確:不管你有沒有用 NSURLProtocol 對 app 中的全部網絡請求作統一處理,這些網絡請求的發起者都應該是無感知的。舉個例子,在某個業務場景下,我使用自定義的 URLSession 發起網絡請求,並實現各個代理方法來處理網絡請求各個階段的事件。若是這個網絡請求被 NSURLProtocol 攔截,仍然須要保證當初實現的各個代理方法都能被如期調用。爲此,蘋果定義了 NSURLProtocolClient
協議,協議方法覆蓋了網絡請求完整的生命週期。只要你在攔截以後重發的請求的各階段適時、完整地調用了協議中的方法,那麼最初的請求發起者便對「攔截」這件事毫無感知了,它的代理事件或者回調的 block 都會在正確的時間被執行,不管這個請求最初是個 NSURLSessionDownloadTask
仍是 NSURLConnection
。從這個角度來講,NSURLProtocol 是一個底層的攔截。web
二、不少介紹 NSURLProtocol 的文章,會在每一個 startLoading
方法的實現中,都建立 NSURLSession 實例,這是很是低效、失當的作法,具體緣由其實和 NSURLProtocol 無關了,這是 NSURLSession 使用失當的問題。正確的實現應該是模擬 AFNetworking 的 SessionManager
,共享一個 session 實例,卻能夠將歸屬於每個 task 的回調事件交由每個 NSURLProtocol 實例處理,具體能夠參考官方給出的 NSURLProtocol demo。或者,甚至能夠直接使用 AFNetworking 來對攔截後的請求進行重發。objective-c
三、攔截重發一個 Request 以後,記得使用 setProperty:forKey:inRequest:
方法對該 Request 進行標記,防止進入死循環。編程
四、經過配置 Configuration
自定義的 Session 發出的請求,默認是沒法被攔截到的,由於 NSURLSessionConfiguration
的屬性 protocolClasses
裏面,默認不包含咱們自定義的 NSURLProtocol。這時,能夠 hook protocolClasses 方法,加入咱們本身的 protocol。小程序
五、有的同窗可能會糾結,最初的網絡請求若是是一個 NSURLSessionDownloadTask
,它須要處理帶有已寫入數據、完整數據等信息的回調方法,而在 NSURLProtocol 中被攔截以後,統一採用 NSURLSessionDataTask 來重發,那當初的下載獨有的代理方法,還能被正確執行嗎?答案是確定的,緣由參考第一條。其實經過 NSURLProtocol 只提供了 NSURLRequest 來初始化的方法就能夠看出來,在 NSURLProtocol 中,咱們不須要關注最初的任務是何種 task,由於不管最初是什麼類型的 task,到 protocol 的初始化這裏時,你已經沒法獲知它最初的 task 類型。api
做者: 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;
複製代碼
參考:
**做者:**這個湯圓沒有餡
提到三方登陸分享,第一反應大概是友盟、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
註冊各個平臺,再如圖三調用受權登陸的方法。
看了一下源碼,實現原理以下:
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+,期待你的加入。