「 iOS 知識小集 」2018 · 第 24 期

上週公衆號發佈的如下文章:html

本期知識小集的主要內容包括:ios

  • 再談數組、集合、字典與 hash、isEqual 方法的關聯
  • 使用 Keychain 存儲登陸態須要注意的一個坑
  • 給 UIView 添加陰影
  • 比較三種網絡框架上傳圖片過程當中的不一樣點?
  • 經過 runtime 控制導航欄的 hidden 屬性
  • 關於 IAP 丟單的處理

再談數組、集合、字典與 hash、isEqual 方法的關聯

做者: halohilyweb

咱們或多或少了解,Objective-C 中的 NSArray、NSSet、NSDictionary 與 NSObject 及其子類對象的 hash、isEqual 方法有許多聯繫,這篇小集講一下其中的一些細節。編程

NSArray 容許添加劇復元素,添加元素時不查重,因此不調用上述兩個方法。在移除元素時,會對當前數組內的元素進行遍歷,每一個元素的 isEqual 方法都會被調用(使用 remove 方法傳入的元素做爲參數),全部返回真值的元素都被移除。在字典中,不涉及 hash 方法。小程序

NSSet 不容許添加劇復元素,因此添加新元素時,該元素的 hash 方法會被調用。若集合中不存在與此元素 hash 值相同的元素,則它直接被加入集合,不調用 isEqual 方法;若存在,則調用集合內的對應元素的 isEqual 方法,返回真值則判等,不加入,處理結束。若返回 false,則斷定集合內不存在該元素,將其加入。數組

從集合中移除元素時,首先調用它的 hash 方法。若集合中存在與其 hash 值相等的元素,則調用該元素的 isEqual 方法,若真值則判等,進行移除;若不存在,則會依次調用集合中每一個元素的 isEqual 方法,只要找到一個返回真值的元素,就進行移除,並結束整個過程。(因此這樣會有其餘知足 isEqual 方法但卻被漏掉未被移除的元素)。調用 contains 方法時,過程相似。緩存

所以,若某自定義對象會被加入到集合或做爲字典的 key 時,須要同時重寫 isEqual 方法和 hash 方法。這樣,若集合中某元素存在,則調用它的 contains 和 remove 方法時,能夠在 O(1) 完成查詢。不然,查詢它的時間複雜度提高爲 O(n)。安全

值得注意的是,NSDictionary 的鍵和值都是對象類型便可。可是被設爲鍵的對象須要遵照 NSCopying 協議。服務器

使用 Keychain 存儲登陸態須要注意的一個坑

做者: KANGZUBIN網絡

今天要討論的這個問題你可能永遠都不會遇到,並且絕大部分狀況下你很難在開發中事先預料到它將來可能會發生,可是一旦不幸發生了,可能就是一個很嚴重的線上問題,慘痛教訓。

咱們一般會在 Keychain(鑰匙串)中存儲一些密碼、用戶登陸態等敏感數據,一是能夠提升保存數據的安全性;二是當用戶卸載 App 後從新安裝,能夠自動登陸保留上次的登陸態;三是同一開發者帳號下的不一樣 App,若是是採用同一套帳戶體系,就能夠經過 Keychain Groups 共享登陸態。

咱們的 App 以前都是隻把用戶的登陸態保存在 Keychain 中,並在 App 啓動時去讀取它,這一直也都沒什麼問題。前一段時間咱們的 App 因爲業務合規的緣由審覈被拒,按照蘋果的要求不得不把 App 從公司的 A 開發者帳號轉讓到 B 開發者帳號下(公司旗下有不少不一樣主體的開發者帳號),轉讓過程很順利,但發版後短期內收到大面積的用戶反饋說,更新新版本後提示「登陸失效,須要從新登陸」。

緣由很容易就能夠猜到,App 從 A 轉讓到 B,就沒法讀取保存在 A 帳號下的 Keychain 數據了,用戶更新版本覆蓋安裝後,打開 App 也就沒法獲取以前的登陸態了。

並且對於這種已經發生的問題,咱們彷佛也沒有什麼有效的補救措施,臨時加急再發一版彷佛也解決不了問題,由於以前的 Keychain 數據就是讀取不到了,總不能再把 App 轉讓回去吧,😂

那麼如何未雨綢繆預防之後再發生這種由於轉讓 App 致使存儲在 Keychain 中的登陸態丟失讀取不到呢?(雖然出現轉讓 App 的機率很是低)

咱們在新版本中採用了一種兼容的方法:把用戶的登陸態同時加密存儲在本地緩存(Sandbox)和 Keychain 中,在 App 啓動時,優先從 Keychain 中讀取,若是 Keychain 中取不到,就從本地緩存中取(而後再把本地緩存的同步到 Keychain 中,由於即便 App 轉讓了,用戶更新版本覆蓋安裝後 Sandbox 中的數據是不會變的),若是兩處都取不到,就認爲未登陸。

你有沒有更好的解決方案?歡迎留言討論。

另外,有不少人經過 Keychain 來存儲設備惟一標示符,也須要注意這個問題。

關於 Keychain 如何使用,能夠參考蘋果官方文檔:GenericKeychain,而關於 Keychain 濫用問題的討論,能夠看 V2EX 的這個帖子

給 UIView 添加陰影

做者: Lefe_x

給 UIView 添加陰影看似簡單,若是操做不當也可能會浪費你一些時間。有時候明明添加了陰影但是在 UI 上卻沒顯示出來,尤爲涉及到 cell 複用的狀況。這裏總結幾條陰影不顯示的緣由:

  • 是否設置了 masksToBounds 爲 YES,設置爲 masksToBounds=YES,陰影不顯示;
  • 設置陰影時 view 的 frame 是否爲 CGRectZero,若是是,即便設置陰影后修改 frame 不爲 CGRectZero 時,也不會顯示陰影;
  • 使用自動佈局時每每會遇到 frame 爲 CGRectZero 時設置陰影無效,這時可使用 layoutIfNeeded 方法;

經過 layer 設置陰影

// 陰影的顏色
self.imageView.layer.shadowColor = [UIColor blackColor].CGColor;
self.imageView.layer.shadowOpacity = 0.8;
// 陰影的圓角
self.imageView.layer.shadowRadius = 1;
// 陰影偏離的位置 (100, 50) x 方向偏離 100,y 偏離 50 正向,若是是負數正好爲相反的方向
self.imageView.layer.shadowOffset = CGSizeMake(3, 4);
複製代碼

經過 shadowPath 設置陰影

經過這種方式設置的陰影能夠自定義陰影的形狀,它會使用在 layer 上設置的屬性,好比 shadowRadius。

UIEdgeInsets edges = UIEdgeInsetsMake(15, 10, 15, 10);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(-edges.left, -edges.top, CGRectGetWidth(self.imageView.frame) + edges.left + edges.right, CGRectGetHeight(self.imageView.frame) + edges.top + edges.bottom)];
self.imageView.layer.shadowPath = path.CGPath;
複製代碼

比較三種網絡框架上傳圖片過程當中的不一樣點?

做者: 陳滿iOS

AFNetworking 上傳圖片的步驟是利用圖片設置到 request 的 HTTPBodyStream 中去,而後利用帶有圖片的 request 新建 task 上傳。HYNetworking 內部實現上傳圖片的時候,其實就是採用 AFNetworking 關於上傳圖片的 API,都是 AFNetworking 裏面一個 API。XMNetworking 上傳圖片請求也是基於 AFNetworking 上傳進行的封裝,不過比 HYNetworking 更加隱晦而已,另外它封裝了上次圖片數組的方法。

AFNetworking

  1. 壓縮轉換:UIImage 實例對象經過 UIImageJPEGRepresentation (壓縮)轉換爲 NSData,下面稱之爲 imageData。
  2. 信息整合:將 imageData 與文件名 fileName,文件路徑 name,類型名 mimeType 整合成圖片模型(AFHTTPBodyPart)的一個對象 bodyPart 中去。
  3. 添加圖片模型:將上面新建好的圖片模型對象 bodyPart,向圖片輸入流(AFMultipartBodyStream)的對象 bodyStream 的數組屬性(HTTPBodyParts)添加。
  4. 設置 request 的 HTTPBodyStream 屬性爲 bodyStream:封裝爲 requestByFinalizingMultipartFormData
  5. 將圖片模型對象 formData 用 AFNetwork 的 POST 請求與 uploadTaskWithStreamedRequest 方法進行上傳。

HYBNetworking

  1. 壓縮轉換:UIImage 實例對象經過 UIImageJPEGRepresentation 壓縮轉換爲 NSData,下面稱之爲 imageData。
  2. 信息整合:利用 AFNetwork的appendPartWithFileData,將 imageData 與文件名 fileName,文件路徑 name,類型名 mimeType 整合成圖片模型(AFStreamingMultipartFormData)的一個對象 formData 中去。
  3. 將圖片模型對象 formData 用 AFNetwork 的 POST 請求與 uploadTaskWithStreamedRequest 方法進行上傳。

XMNetworking

  1. 壓縮轉換:UIImage 實例對象經過 UIImageJPEGRepresentation 壓縮轉換爲 NSData,下面稱之爲 imageData。
  2. 信息整合:利用 AFNetwork的appendPartWithFileData,將 imageData 與文件名 fileName,文件路徑 name,類型名 mimeType 整合成圖片模型(XMUploadFormData)的一個對象 formData 中去。
  3. 添加圖片模型:向管理器的圖片模型數組 uploadFormDatas 添加上面新建好的圖片模型對象 formData。
  4. 遍歷圖片模型數組,得到圖片模型,利用 AFNetwork 的 POST 請求與 uploadTaskWithStreamedRequest 方法進行上傳。

【總結】 可見,上面三種框架都是基於 AFNetworking 進行的封裝,實質的流程仍是同樣的。上傳圖片的流程圖以下所示。

經過 runtime 控制導航欄的 hidden 屬性

在項目中,有時候會遇到某些個頁面須要隱藏導航欄,通常狀況下,咱們會在 viewWillAppear 和 viewDidDisappear 去設置 navigationBar 的 hidden 屬性,如圖一。

這裏介紹另外一種方法,經過 runtime 去控制。

創建 vc 的 category,聲明 Bool 類型的 hideNavigationBar 屬性。主要思路是:重寫 initialize 方法,而且自定義一個方法經過 runtime 去替代系統的 viewWillAppear,在該自定義方法裏,就是去設置 navigationBar 的 hidden 屬性。具體代碼如圖二。

代碼中用到的幾個 runtime 方法簡單說明下:

//獲取類中的方法實現
    class_getMethodImplementation
//替換Method
    method_exchangeImplementations
//獲取類中的某個實例方法
    class_getInstanceMethod
//關聯對象,至關於 setValue:forKey 
    objc_setAssociatedObject
複製代碼

關於使用方法,因爲 hideNavigationBar 默認是 NO,因此只在須要隱藏導航欄的頁面調用便可,代碼如圖三。

關於 IAP 丟單的處理

做者: 高老師很忙

作 IAP(In-App Purchase)功能都有可能遇到丟單的問題,丟單是用戶已經付款,可是由於某種緣由客戶端沒有辦法處理後續的操做,好比說根本沒有收到蘋果支付成功的回調,或者在與服務器驗證票據過程當中斷網等等。若是處理很差,很容易擊潰用戶的對產品的信用度。

蘋果的推薦作法是合理使用 transaction,在 AppDelegate.m 的 application:didFinishLaunchingWithOptions: 方法裏添加 [[SKPaymentQueue defaultQueue] addTransactionObserver:xxx] ;若是尚未調用 [[SKPaymentQueue defaultQueue] finishTransaction:xxx],那麼在你下次啓動 App 的時候,就會在 paymentQueue:updatedTransactions: 回調裏收到未完成的 transaction,而後繼續進行處理,因此須要你在合適的時機去調用 finishTransaction 方法,好比說整個支付流程已經完成(包括已經成功驗證票據)的時候,這個能夠根據你的業務狀況來肯定調用時機,這樣能夠大大下降丟單的機率。不要忘了 removeTransactionObserver 哦!

若是以爲處理丟單的時間有點久,能夠根據實際狀況把相關信息存到本地(若是後續處理流程有須要業務信息的,這種狀況是必需要存本地的),在切換到有網或者切換用戶或者你以爲合適的實際去處理後續流程,這樣也能夠雙保險,能夠把損失降到最低。

關注咱們

歡迎關注咱們的公衆號:iOS-Tips,也歡迎加入咱們的羣組討論問題。能夠公衆號留言 iosflutterwebpwa小程序 等關鍵詞獲取入羣方式。

相關文章
相關標籤/搜索