Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Type Safe Assets Handling in Swift

2,181 views

Published on

Type Safe Assets Handling in Swift

Published in: Engineering
  • Be the first to comment

Type Safe Assets Handling in Swift

  1. 1. Type Safe Resource Handling in Swift 2015/10/13 potatotips #22
  2. 2. About Me @tasanobu Kazunobu Tasaka
  3. 3. 本日の内容 • リソースを静的型付けし、Type Safeに扱う方法 をお話しします。 • リソースとは
 Asset Catalog  UIStoryboard 
 Localizable.strings
  4. 4. • リソースのインスタンス生成時
 String型の値で指定 Objective-C style // Assets Catalog let img = UIImage(named: "Sample") // Storyboard let sb = UIStoryboard(name: "Sample", bundle: nil) .instantiateViewControllerWithIdentifier("Sample") as? SampleViewController // Localizable.strings let str = NSLocalizedString("Sample", comment: “")
  5. 5. 問題点 • コンパイラによるチェックが不可 
 → 指定方法がStringのため💦 • 実行時にリソースの存在チェック 
 → ランタイムエラーが発生するリスクあり • 戻り値の型 : Optional<T> 
 → 使用時にunwrapする必要がある // 存在しない場合 let sb = UIStoryboard(name: UIApplicationDidBecomeActiveNotification, bundle: nil) // Terminating app due to uncaught exception 'NSInvalidArgumentException', // reason: 'Could not find a storyboard named 'Sample' in bundle NSBundle let img: UIImage? = UIImage(named: NSURLErrorDomain) let vc: SampleViewController? = sb.instantiateViewControllerWithIdentifier("Sample") as? SampleViewController
  6. 6. 改善ポイント Swift は Type Safe な言語! • リソースのStringに型情報を持たせる
  7. 7. App Specific Enum extension UIImage { enum Asset: String { case Camera = "Camera" case Home = "Home" case Mail = "Mail" } convenience init!(asset: Asset) { self.init(named: asset.rawValue) } } Asset ID / Enumの対応付け • Initializer: Enumでリソースを指定 • Non Optional な戻り値 (リソースの存在が担保されている)
  8. 8. Usage let camera = UIImage(asset: .Camera) let home = UIImage(asset: .Home) let mail = UIImage(asset: .Mail)
  9. 9. Pros / Cons • Pros 引数を型付けできる → コンパイル時チェックが可能 → Non-optionalな型が戻り値となる • Cons リソースを更新する度にEnum値を更新する必要がある😓
  10. 10. • CLツール : リソース用Swiftコードを自動生成 Asset Catalog (UIImage) UIStoryboard Localizable.strings UIColor • Homebrewに対応
 https://github.com/AliSoftware/SwiftGen SwiftGen  $  brew  install  swiftgen  
  11. 11. Usage: UIStoryboard • コマンドラインを実行 swiftgen-­‐storyboard  /dir/to/storyboards  >  Storyboards.swift
  12. 12. // Storyboards.swift protocol StoryboardScene : RawRepresentable { static var storyboardName : String { get } static func storyboard() -> UIStoryboard static func initialViewController() -> UIViewController func viewController() -> UIViewController static func viewController(identifier: Self) -> UIViewController } extension StoryboardScene where Self.RawValue == String { static func storyboard() -> UIStoryboard { return UIStoryboard(name: self.storyboardName, bundle: nil) } static func initialViewController() -> UIViewController { return storyboard().instantiateInitialViewController()! } func viewController() -> UIViewController { return Self.storyboard().instantiateViewControllerWithIdentifier(self.rawValue) } static func viewController(identifier: Self) -> UIViewController { return identifier.viewController() } } via https://github.com/AliSoftware/SwiftGen
  13. 13. // Storyboards.swift extension UIStoryboard { struct Scene { enum Wizard : String, StoryboardScene { static let storyboardName = "Wizard" case CreateAccount = "CreateAccount" static func createAccountViewController() -> CreateAccViewController { return Wizard.CreateAccount.viewController() as! CreateAccViewController } case ValidatePassword = "Validate_Password" static func validatePasswordViewController() -> UIViewController { return Wizard.ValidatePassword.viewController() } } enum Message : String, StoryboardScene { static let storyboardName = "Message" case Composer = "Composer" static func composerViewController() -> UIViewController { return Message.Composer.viewController() } case URLChooser = "URLChooser" static func urlChooserViewController() -> XXPickerViewController { return Message.URLChooser.viewController() as! XXPickerViewController } } } struct Segue { enum Message : String { case Custom = "Custom" case Back = "Back" case NonCustom = "NonCustom" } } } Storyboard IDに対応 Storyboardファイルに対応 via https://github.com/AliSoftware/SwiftGen
  14. 14. Usage // Initial VC let initialVC = UIStoryboard.Scene.Wizard.initialViewController() // Generic ViewController constructor, returns a UIViewController instance let validateVC = UIStoryboard.Scene.Wizard.ValidatePassword.viewController() // Dedicated type var that returns the right type of VC (CreateAccViewController here) let createVC = UIStoryboard.Scene.Wizard.createAccountViewController() override func prepareForSegue(_ segue: UIStoryboardSegue, sender sender: AnyObject?) { switch UIStoryboard.Segue.Message(rawValue: segue.identifier)! { case .Custom: // Prepare for your custom segue transition case .Back: // Prepare for your custom segue transition case .NonCustom: // Prepare for your custom segue transition } } via https://github.com/AliSoftware/SwiftGen
  15. 15. まとめ • App Specific Enum を利用すると
 静的型付けしてリソースを扱える😄 • SwiftGen: リソース用コードを自動生成可能😄
  16. 16. References • SwiftGen
 https://github.com/AliSoftware/SwiftGen
 
 • WWDC’15: Swift in Practice
 https://developer.apple.com/videos/wwdc/ 2015/?id=411
  17. 17. ご静聴ありがとうございました 🙇

×