Date post: | 12-Apr-2017 |
Category: |
Engineering |
Upload: | kaz-yoshikawa |
View: | 135 times |
Download: | 2 times |
Idioms in SwiftKaz Yoshikawa
May 2016
About me
Kaz Yoshikawa• Electricwoods LLC 代表 / Digital Lynx Systems Inc. 副代表
• e-mail: [email protected]
• LinkedIn: https://www.linkedin.com/in/kazyoshikawa
• Working History
• Adobe Systems (Tokyo)
• Lionbridge (Tokyo)
• Quark (Tokyo / Denver)
• Hummingbird Communications (Mt. View, USA)
• Fact International (Vancouver, Canada)
• Perle Systems (Toronto, Canada), etc.
Engineering
将棋盤Kit
What is Idiom?
Optional
guard let• 二つの引数が nil でない事を保証する
func add(a: Int?, _ b: Int?) -> Int? {
guard let a = a, let b = b else { return nil }
return a + b }
if let• if let を使う
func add(a: Int?, _ b: Int?) -> Int? {
if let a = a, let b = b { return a + b } return nil
}
where• guard let で0以上を保証する
func add(a: Int?, _ b: Int?) -> Int? { guard let a = a, let b = b where a >= 0 && b >= 0 else { return nil } return a + b }
• if let でも0以上を保証する func add(a: Int?, _ b: Int?) -> Int? { if let a = a, let b = b where a >= 0 && b >= 0 { return a + b } return nil }
nil-coalescing Operator• nil の場合は 0 として扱う func add(a: Int?, b: Int?) -> Int {
return (a ?? 0) + (b ?? 0)
}
Switch
Optional in Switch• 実は optional も switch 文に使える
func countryName(identifier: String?) -> String? { switch identifier { case "JP"?: return "Japan" case "GB"?: return "England" case "US"?: return "U.S.A." default: return nil } }
Late InitializingImmutable Variables
• 初期値を後で設定する不定変数
let color: UIColor // "= value"
switch value % 3 { case 0: color = UIColor.whiteColor() case 1: color = UIColor.redColor() default: fatalError() }
• 初期化しないケースがあると、コンパイルエラー
Complex switch casesfor thing in things { switch thing { case 0 as Int: print("zero as an Int") case 0 as Double: print("zero as a Double") case let someInt as Int: print("an integer value of \(someInt)") case let someDouble as Double where someDouble > 0: print("a positive double value of \(someDouble)") case is Double: print("some other double value") case let someString as String: print("a string value of \"\(someString)\"") case let (x, y) as (Double, Double): print("an (x, y) point at \(x), \(y)") case let movie as Movie: print("Movie:'\(movie.name)'") default: print("something else") } }
Implicitly Unwrapped Optional
Implicitly Unwrapped Optional with if statement
• Implicitly Unwrapped Optional でも if let は 使える
let a: Int! if let a = a { print("\(a)") }
Implicitly Unwrapped Optional with guard statement
• Implicitly Unwrapped Optional でも guard は 使える
class MyObject { var value: Int! = nil func some() { guard let value = value else { return } print("\(value)") } func other() { guard value != nil else { return } print("\(value)") } }
Associated Values
Defining Associated Value
enum Element { case String(Swift.String) case Boolean(Bool) case Integer(Int) case Float(Swift.Float) case Dictionary([Swift.String: Element]) case Array([Element]) case Null }
let integer = Element.Integer(42) let city = Element.String("Tokyo") let cities = Element.Array([city]) let dictionary = Element.Dictionary(["items": array])
Extracting Associated Values Using switch Statement
• Associated Value を Switch文で取り出す
switch element { case .String(let string): print("string: \(string)") case .Boolean(let value): print("boolean: \(value)") case .Integer(let value): print("ineteger: \(value)") case .Float(let value): print("float: \(value)") case .Dictionary(let dictionary): print("dictionary: \(dictionary)") case .Array(let array): print("array: \(array)") case .Null: print("null") }
Extracting Associated Values using if Statement
• If 文でも取り出せます
let element1: Element = … if case .String(let string) = element1 { print("\(string)") }
• Optional な場合でも取り出せます
let element: Element? = … if case .String(let string)? = element1 { print("\(string)") }
Extracting Associated Values
• division -> members -> person -> name
let name = Element.String("John") let john = Element.Dictionary(["name": name]) let members = Element.Array([john]) let group = Element.Dictionary(["members": members])
• 一発で取り出せる
if case .Dictionary(let group) = group, case .Array(let members)? = division["members"], case .Dictionary(let member)? = members.first, case .String(let name)? = member["name"] { print("\(name)") // John }
Closure
Basic Closureclass MyViewController: UIViewController { var state: Bool = false func toggle(animated: Bool) { let closure = { self.view.backgroundColor = self.state ? UIColor.redColor() : UIColor.whiteColor() self.state = !self.state } if animated { UIView.animateWithDuration(0.3) { closure() // <-- Here!! } } else { closure() // <-- Here!! } } }
Basic Closureclass MyViewController: UIViewController { var state: Bool = false func toggle(animated: Bool) { let closure = { self.view.backgroundColor = self.state ? UIColor.redColor() : UIColor.whiteColor() self.state = !self.state } if animated { UIView.animateWithDuration(0.3) { closure() // <-- Here!! } } else { closure() // <-- Here!! } } }
Execute on Main Thread func dispatch_sync_main(block: () -> Void) { if NSThread.isMainThread() { block() } else { dispatch_sync(dispatch_get_main_queue()) { () -> Void in block() } } }
dispatch_sync_main { self.tableView.reloadData() }
Execute on Main Thread func dispatch_sync_main(block: () -> Void) { if NSThread.isMainThread() { block() } else { dispatch_sync(dispatch_get_main_queue()) { () -> Void in block() } } }
dispatch_sync_main { self.tableView.reloadData() }
Execute on Main Thread func dispatch_sync_main(block: () -> Void) { if NSThread.isMainThread() { block() } else { dispatch_sync(dispatch_get_main_queue()) { () -> Void in block() } } }
dispatch_sync_main { self.tableView.reloadData() }
Initialize Immutable Variable Using Closure
• closure と switch 文を使うとかっこよく書ける let color: UIColor = { switch value % 2 { case 0: return UIColor.whiteColor() case 1: return UIColor.redColor() default: fatalError() } }() // "()" !!
Initialize Immutable Variable Using Closure
• closure と switch 文を使うとかっこよく書ける let color: UIColor = { switch value % 2 { case 0: return UIColor.whiteColor() case 1: return UIColor.redColor() default: fatalError() } }() // "()" !!
Changing Behavior with Using Closure
typealias DrawingHandler = (UIPanGestureRecognizer)->()
class MyView: UIView { func panGesture(sender: UIPanGestureRecognizer) { self.drawingHandler(sender) } var drawingHandler: DrawingHandler! let ovalGesture: DrawingHandler = { gesture in // draw oval } let rectangleGesture: DrawingHandler = { gesture in // draw rectangle } }
Changing Behavior with Using Closure
typealias DrawingHandler = (UIPanGestureRecognizer)->()
class MyView: UIView { func panGesture(sender: UIPanGestureRecognizer) { self.drawingHandler(sender) } var drawingHandler: DrawingHandler! let ovalGesture: DrawingHandler = { gesture in // draw oval } let rectangleGesture: DrawingHandler = { gesture in // draw rectangle } }
lazy
When should I use lazy?• 処理が重くて初期化時に実行するのは不都合
• 大人の理由で init で初期化できないプロパティ
Using lazy varclass MyObject {
lazy var path: String = { return NSBundle.mainBundle() .pathForResource("text", ofType: "txt")! }()
lazy var text: String = { return try! String(contentsOfFile: self.path) }() }
Initializing code per instance
• 何回呼ばれてもインスタンス毎に一度のみ初期化するコード
class MyView: UIView {
override func layoutSubviews() { print("MyView: \(#function)") super.layoutSubviews() setup() }
private lazy var setup: (()->()) = { print("MyView: \(#function)") // さまざまな初期化のコード return {} }() }
http://qiita.com/codelynx/items/f0243d631f2448e89026
Singleton
Singleton• 典型的なシングルトン class Manager { static let sharedManager = Manager() private init() { } }
• クロージャーを使ったシングルトン
class Manager { static var sharedManager: Manager = { return Manager() }() private init() { } }
http://qiita.com/codelynx/items/a936afe0a45d4cf5abfb
Updating C style `for` statement
http://qiita.com/codelynx/items/899c26dd2cbdba7d2b00
for var i = 0 ; i < 100 ; i++// C-Style for statement for var i = 0 ; i < 100 ; i++ { print("\(i)") }
// Swift 3.0 ready (0 ..< 100).forEach { print("\($0)") }
// Swift 3.0 ready for i in (0 ..< 100) { print("\(i)") }
for var i = 99 ; i >= 0 ; i--// C-Style for statement for var i = 99 ; i >= 0 ; i-- { print("\(i)") }
// Swift 3.0 ready (0 ..< 100).reverse().forEach { print("\($0)") }
// Swift 3.0 ready for i in (0 ..< 100).reverse() { print("\(i)") }
for var i = 0; i < 100 ; i += 2// C-Style for statement for var i = 0; i < 100 ; i += 2 { print("\(i)") }
// Swift 3.0 ready 0.stride(to: 100, by: 2).forEach { print("\($0)") }
for var i = 98 ; i >= 0 ; i -= 2
// C-Style for statement for var i = 98 ; i >= 0 ; i -= 2 { print("\(i)") }
// Swift 3.0 ready 98.stride(through: 0, by: -2).forEach { print("\($0)") }
// Swift 3.0 ready
0.stride(to: 100, by: 2).reverse().forEach { print("\($0)") }
// Swift 3.0 ready for i in 0.stride(to: 100, by: 2).reverse() { print("\(i)") }
for without increment• 次の再初期化式の指定がなく、刻みが不定の場合 // C-Style for statement for var i = 0 ; i < 100 ; { print("\(i)") if (i * i) % 2 == 0 { i += 1 } else { i += 2 } }
// Swift 3.0 ready var i = 0 while i < 100 { print("\(i)") if (i * i) % 2 == 0 { i += 1 } else { i += 2 } }
Computed Properties and Property Observer
Custom Propertyclass MyObject {
private var _name: String = ""
var name: String { get { return _name } set { _name = newValue } }
}
Property Observerclass MyView: UIView {
var name: String = "" { didSet { self.setNeedsLayout() } }
}
Wrap Up
Wrap up• 知っていても、0.2秒で思い出せない記法はいろいろある
• Open Source を散策して先人達の記法を参考に
• 気がついた記法があれば、playground などにメモ
• 時々、swift 文法書を眺め直してみよう