本文是投稿文章,譯者:ShawnPan
"小黃鴨"法不僅適用於debug,也適用於學習新知識。表達是最好的吸收。本文原文發表在realm.io上。我翻譯並整理成此文。希望可以為國內的iOS朋友提供一些資料。
LayoutGuide
在iOS 9.0和 OS X 10.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。然後選取你手動跳轉的代碼,大力地按下刪除鍵吧!