SlideShare une entreprise Scribd logo
1  sur  17
Télécharger pour lire hors ligne
Type Safe Resource Handling
in Swift
2015/10/13
potatotips #22
About Me
@tasanobu
Kazunobu Tasaka
本日の内容
• リソースを静的型付けし、Type Safeに扱う方法
をお話しします。
• リソースとは

Asset Catalog  UIStoryboard 

Localizable.strings
• リソースのインスタンス生成時

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: “")
問題点
• コンパイラによるチェックが不可 

→ 指定方法が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
改善ポイント
Swift は Type Safe な言語!
• リソースのStringに型情報を持たせる
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 な戻り値 (リソースの存在が担保されている)
Usage
let camera = UIImage(asset: .Camera)
let home = UIImage(asset: .Home)
let mail = UIImage(asset: .Mail)
Pros / Cons
• Pros
引数を型付けできる
→ コンパイル時チェックが可能
→ Non-optionalな型が戻り値となる
• Cons
リソースを更新する度にEnum値を更新する必要がある😓
• CLツール : リソース用Swiftコードを自動生成
Asset Catalog (UIImage) UIStoryboard
Localizable.strings UIColor
• Homebrewに対応

https://github.com/AliSoftware/SwiftGen
SwiftGen
	
  $	
  brew	
  install	
  swiftgen	
  
Usage: UIStoryboard
• コマンドラインを実行
swiftgen-­‐storyboard	
  /dir/to/storyboards	
  >	
  Storyboards.swift
// 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
// 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
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
まとめ
• App Specific Enum を利用すると

静的型付けしてリソースを扱える😄
• SwiftGen: リソース用コードを自動生成可能😄
References
• SwiftGen

https://github.com/AliSoftware/SwiftGen



• WWDC’15: Swift in Practice

https://developer.apple.com/videos/wwdc/
2015/?id=411
ご静聴ありがとうございました
🙇

Contenu connexe

Tendances

Tendances (11)

忙しい人のためのBackbone.jsとAngular.js入門
忙しい人のためのBackbone.jsとAngular.js入門忙しい人のためのBackbone.jsとAngular.js入門
忙しい人のためのBackbone.jsとAngular.js入門
 
これからのJavaScriptの話
これからのJavaScriptの話これからのJavaScriptの話
これからのJavaScriptの話
 
20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会
 
introduction to Marionette.js (jscafe14)
introduction to Marionette.js (jscafe14)introduction to Marionette.js (jscafe14)
introduction to Marionette.js (jscafe14)
 
jvmlang.daitokai 1.0.0 MinCamlJを作ってみた
jvmlang.daitokai 1.0.0 MinCamlJを作ってみたjvmlang.daitokai 1.0.0 MinCamlJを作ってみた
jvmlang.daitokai 1.0.0 MinCamlJを作ってみた
 
Marionettejs getting started
Marionettejs getting startedMarionettejs getting started
Marionettejs getting started
 
BACKBONE.JSにJasmineでテストコード書いてみた (LT資料)
BACKBONE.JSにJasmineでテストコード書いてみた (LT資料)BACKBONE.JSにJasmineでテストコード書いてみた (LT資料)
BACKBONE.JSにJasmineでテストコード書いてみた (LT資料)
 
JAWS-UG CLI #14 LT 【”Waiters”機能の使いドコロ】
JAWS-UG CLI #14 LT 【”Waiters”機能の使いドコロ】JAWS-UG CLI #14 LT 【”Waiters”機能の使いドコロ】
JAWS-UG CLI #14 LT 【”Waiters”機能の使いドコロ】
 
NoSQL and JavaScript 2013-02-09
NoSQL and JavaScript 2013-02-09NoSQL and JavaScript 2013-02-09
NoSQL and JavaScript 2013-02-09
 
XIBで作ったカスタムセルの扱い方
XIBで作ったカスタムセルの扱い方XIBで作ったカスタムセルの扱い方
XIBで作ったカスタムセルの扱い方
 
覚醒!JavaScript
覚醒!JavaScript覚醒!JavaScript
覚醒!JavaScript
 

En vedette

En vedette (11)

Objective-C Generics
Objective-C GenericsObjective-C Generics
Objective-C Generics
 
My first tvOS
My first tvOSMy first tvOS
My first tvOS
 
個人で開発したアプリがベスト新着に選ばれた話
個人で開発したアプリがベスト新着に選ばれた話個人で開発したアプリがベスト新着に選ばれた話
個人で開発したアプリがベスト新着に選ばれた話
 
Caffeでお手軽本格ディープラーニングアプリ @potatotips
Caffeでお手軽本格ディープラーニングアプリ @potatotipsCaffeでお手軽本格ディープラーニングアプリ @potatotips
Caffeでお手軽本格ディープラーニングアプリ @potatotips
 
Introducing Cardio
Introducing CardioIntroducing Cardio
Introducing Cardio
 
Xcode7時代のアプリ配布
Xcode7時代のアプリ配布Xcode7時代のアプリ配布
Xcode7時代のアプリ配布
 
Swift Scriptingのすゝめ
Swift ScriptingのすゝめSwift Scriptingのすゝめ
Swift Scriptingのすゝめ
 
View Monitoring Tips
View Monitoring TipsView Monitoring Tips
View Monitoring Tips
 
HealthKitで日別のデータを一度に取得する
HealthKitで日別のデータを一度に取得するHealthKitで日別のデータを一度に取得する
HealthKitで日別のデータを一度に取得する
 
watchOS2 tips
watchOS2 tipswatchOS2 tips
watchOS2 tips
 
tvOSネイティブアプリを作る
tvOSネイティブアプリを作るtvOSネイティブアプリを作る
tvOSネイティブアプリを作る
 

Similaire à Type Safe Assets Handling in Swift

アップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられるアップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられる
Brian Gesiak
 
Storyboard
StoryboardStoryboard
Storyboard
Akura Pi
 
SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2
Nobuhiro Nakajima
 

Similaire à Type Safe Assets Handling in Swift (20)

IgGrid 入門編
IgGrid 入門編IgGrid 入門編
IgGrid 入門編
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
 
アップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられるアップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられる
 
Knockout.js を利用したインタラクティブ web アプリケーション開発
Knockout.js を利用したインタラクティブ web アプリケーション開発Knockout.js を利用したインタラクティブ web アプリケーション開発
Knockout.js を利用したインタラクティブ web アプリケーション開発
 
Azure で Serverless 初心者向けタッチ&トライ
Azure で Serverless 初心者向けタッチ&トライAzure で Serverless 初心者向けタッチ&トライ
Azure で Serverless 初心者向けタッチ&トライ
 
Storyboard
StoryboardStoryboard
Storyboard
 
Road to UI Library
Road to UI LibraryRoad to UI Library
Road to UI Library
 
Blocksの活用法
Blocksの活用法Blocksの活用法
Blocksの活用法
 
jQuery超入門編
jQuery超入門編jQuery超入門編
jQuery超入門編
 
SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2
 
Enhancements with 3D Touch
Enhancements with 3D TouchEnhancements with 3D Touch
Enhancements with 3D Touch
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
 
HTML5最新動向
HTML5最新動向HTML5最新動向
HTML5最新動向
 
Active Directoryデータの "大きい整数"
Active Directoryデータの "大きい整数"Active Directoryデータの "大きい整数"
Active Directoryデータの "大きい整数"
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
 
HTML5&API総まくり
HTML5&API総まくりHTML5&API総まくり
HTML5&API総まくり
 
初めての Data api cms どうでしょう - 大阪夏の陣
初めての Data api   cms どうでしょう - 大阪夏の陣初めての Data api   cms どうでしょう - 大阪夏の陣
初めての Data api cms どうでしょう - 大阪夏の陣
 
Ll xcode
Ll xcodeLl xcode
Ll xcode
 
Windows スクリプトセミナー WMI編 VBScript&WMI
Windows スクリプトセミナー WMI編 VBScript&WMIWindows スクリプトセミナー WMI編 VBScript&WMI
Windows スクリプトセミナー WMI編 VBScript&WMI
 
20150207コデアルエンジニア学生向けハッカソン就活イベント発表資料
20150207コデアルエンジニア学生向けハッカソン就活イベント発表資料20150207コデアルエンジニア学生向けハッカソン就活イベント発表資料
20150207コデアルエンジニア学生向けハッカソン就活イベント発表資料
 

Type Safe Assets Handling in Swift

  • 1. Type Safe Resource Handling in Swift 2015/10/13 potatotips #22
  • 3. 本日の内容 • リソースを静的型付けし、Type Safeに扱う方法 をお話しします。 • リソースとは
 Asset Catalog  UIStoryboard 
 Localizable.strings
  • 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. 問題点 • コンパイラによるチェックが不可 
 → 指定方法が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. 改善ポイント Swift は Type Safe な言語! • リソースのStringに型情報を持たせる
  • 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. Usage let camera = UIImage(asset: .Camera) let home = UIImage(asset: .Home) let mail = UIImage(asset: .Mail)
  • 9. Pros / Cons • Pros 引数を型付けできる → コンパイル時チェックが可能 → Non-optionalな型が戻り値となる • Cons リソースを更新する度にEnum値を更新する必要がある😓
  • 10. • CLツール : リソース用Swiftコードを自動生成 Asset Catalog (UIImage) UIStoryboard Localizable.strings UIColor • Homebrewに対応
 https://github.com/AliSoftware/SwiftGen SwiftGen  $  brew  install  swiftgen  
  • 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. // 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. 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. まとめ • App Specific Enum を利用すると
 静的型付けしてリソースを扱える😄 • SwiftGen: リソース用コードを自動生成可能😄
  • 16. References • SwiftGen
 https://github.com/AliSoftware/SwiftGen
 
 • WWDC’15: Swift in Practice
 https://developer.apple.com/videos/wwdc/ 2015/?id=411