[譯]iOS 9開發小技巧
前言
"小黃鴨"法不僅適用于debug,也適用于學習新知識。表達是最好的吸收。 本文原文 發表在realm.io上。我翻譯并整理成此文。希望可以為國內的iOS朋友提供一些資料。
LayoutGuide
在iOS9.0 和 OS X10.11中,分別有兩個新的類:UILayoutGuide和NSLayoutGuide。他們可以作為一種類似View的對象,參與到AutoLayout的布局約束中。作為一種新的布局解決方案,這兩個類的出現使你無需再創建、顯示無關的View了。舉個栗子,原本需要一個空的UIView占位的地方,現在只需要用UILayoutGuide去替代它就可以了。
// 創建LayoutGuide
let layoutGuideA = UILayoutGuide()
let layoutGuideB = UILayoutGuide()
// 添加到View上
let view: UIView = ...
view.addLayoutGuide(layoutGuideA)
view.addLayoutGuide(layoutGuideB)
// 用UILayoutGuide來添加布局約束
layoutGuideA.heightAnchor.constraintEqualToAnchor(layoutGuideB.heightAnchor).active = true
// 設置Identifier,為了方便DEBUG
layoutGuideA.identifier = "layoutGuideA"
layoutGuideB.identifier = "layoutGuideB"
// ...然后看看他們的Frame吧
print("layoutGuideA.layoutFrame -> \(layoutGuideA.layoutFrame)") NSLayoutAnchor
iOS9中另一個新增的API是NSLayoutAnchor。它的出現不僅僅是讓使用代碼添加約束變得簡潔明了。通過該類強大的靜態檢查能力,還提供了額外的約束正確定保證。舉個栗子,考慮以下使用NSLayoutConstraintAPI創建的約束會出現什么問題:
NSLayoutConstraint *constraint =
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view2
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];這個約束是無效的。因為你將一個X軸上的屬性(leading)同一個Y軸屬性(top)綁定。然而,這個錯誤可以毫無警告地通過編譯,在運行的時候 默默地 就失效了,最終留下一個出錯的布局。由于這個錯誤不會產生任何的日志信息,導致極難debug。假如工程里有許多(成千上萬)這樣的約束代碼,那對于維護來說真是一場噩夢。
好在NSLayoutAnchor利用了"泛型"解決了這個問題。"泛型"現在在Swift和Objective-C中都已經得到了支持。UIView中NSLayoutAnchor相關的存取方法,明確指出了需要哪些繼承自NSLayoutAnchor的子類。這些子類被分為了三類,X軸,Y軸,和尺寸(寬/高),一種類型的Anchor只允許綁定約束到另外一個相同類型的Anchor上。通過指定NSLayoutAnchor中參數的類型,這個API可以通過類型檢查,來避免創建出例子中無效的約束。
我們回到之前的例子,用NSLayoutAnchor來實現一下這個約束:
NSLayoutConstraint *constraint =
[view1.leadingAnchor constraintEqualToAnchor:view2.topAnchor]; 相比舊的API,新的API非常明顯地提升了代碼可讀性。并且,當你傳入錯誤的Anchor類型時,新的API會拋出一個"Incompatible pointer type"警告,因為編譯器知道這個是兩個不同的類。
想要了解更多,請查閱 NSLayoutAnchor官方文檔
HTTPS 和 HTTP
Apple介紹了iOS9中的 App Transport Security ,它要求所有App在默認情況下使用HTTPS來進行網絡請求。由于不是所有的服務器都運行在HTTPS環境下,Apple也提供了相關的方法來禁用ATS。
如果你的App需要請求的網址不可控(比如說UIWebVeiw請求的網站,有可能是HTTP的,也有可能是HTTPS的),那么你應當將Info.plist文件中的NSAllowsArbitraryLoads設置為YES,來完全禁用ATS。出于數據安全考慮,在完全禁用ATS的情況下,你也應該為某些重要的站點打開ATS。你可以通過NSExceptionDomainskey來禁用/啟用特定的站點的ATS。參照如下圖片:
該plist文件允許用戶在HTTP環境下下載文件,但是只能在HTTPS情況下訪問"workflow.is"
需要提醒的是,ATS的設置只針對當前bundle。這意味著你不僅需要在你主項目的info.plist中添加ATS相關的Key,同時也需要在其他bundle下的info.plist中添加相關配置。
關于iOS9的適配,github上有一個中文項目 iOS9AdaptationTips 可以提供很大的幫助。
Storyboard Reference
Storyboard真是讓人又愛又恨,每個在多人合作項目中使用Storyboard的人,都遇到過Storyboard文件的沖突。類似的沖突解決起來比較棘手,常常是以回滾告終。這一點直接造成了一些團隊放棄使用Storyboard開發而推薦純代碼布局。
如果需要使用Storyboard,但又想最大化地避免沖突呢?最好的方法就是將UI劃分的更小的、不同的Storyboard文件中。在過去如果想要做到這一點,意味跨Storyboard的跳轉方法,需要在代碼里完成:
UIStoryboard *destinationStoryboard = [UIStoryboard storyboardWithName:@"StoryboardName" bundle:nil]; DestinationViewController *vc = [destinationStoryboard instantiateViewControllerWithIdentifier:@"identifier"]; //一頓設置 ... [self.navigationController pushViewController:vc animated:YES];
在Xcode7 和 iOS 9中,只需要用Storyboard Reference就可以用Segue輕松實現跨Storyboard的跳轉了。Storyboard Reference的出現,保留了單個Storyboard文件跳轉的優點的同時,提供了多Storyboard文件時利于合并的便利。
開始分割你那巨大的Storyboard文件吧。最快的方法是:
- 縮放Storyboard
- 框選一組邏輯相近的scenes
- 選擇Editor > Refactor to Storyboard...
自動Refactord的故事板文件會為每一個scenes留下一個UIStoryboard Reference,并且在需要的地方自動創建可讀性不好的Storyboard ID。所以就個人來說,我更推薦手動復制scenes到新的故事板文件中,然后在源文件中刪除這些scenes并手動添加Storyboard Reference。
如果你已經有多個故事板文件了,為自己慶祝一下吧——你又可以精簡你的代碼了!從Object庫中拖拽一個UIStoryboard Reference,并配置segue。然后選取你手動跳轉的代碼,大力地按下刪除鍵吧!