idioms in swift 2016 05c

Post on 12-Apr-2017

135 Views

Category:

Engineering

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Idioms in SwiftKaz Yoshikawa

May 2016

About me

Kaz Yoshikawa• Electricwoods LLC 代表 / Digital Lynx Systems Inc. 副代表

• e-mail: kaz@digitallynx.com

• 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 文法書を眺め直してみよう

Thank YouKaz Yoshikawa

kaz@digitallynx.com

top related