Slide 1

Slide 1 text

Visual Format Language͕ ؆୯ʹॻ͚ΔSwiftϥΠϒϥϦ yavfl @matuyuji Cocoaษڧձؔ੢ 2015.4.11

Slide 2

Slide 2 text

@matuyuji safx-dev.blogspot.jp ⌚

Slide 3

Slide 3 text

Auto Layout

Slide 4

Slide 4 text

Auto Layout

Slide 5

Slide 5 text

Auto LayoutΛදݱ͢Δ • XcodeͷετʔϦʔϘʔυ্Ͱ੍໿Λ௥Ճ͢Δ • NSLayoutConstraintͷ constraintWithItem:attribute:relatedBy:toItem:attrib ute:multiplier:constant:Ͱ̍ͭͷ੍໿Λॻ͘ • constraintsWithVisualFormat:options:metrics:view sͰෳ਺ͷ੍໿Λॻ͘

Slide 6

Slide 6 text

Visual Format Language

Slide 7

Slide 7 text

Visual Format Language |-[find]-[findNext]-[findField(>=20)]-| “Auto Layout Guide” from Apple V:[topField]-10-[bottomField]

Slide 8

Slide 8 text

2ͭͷViewΛಉ͡෯Ͱԣʹฒ΂Δ Visual Format Language let dic = ["l": label, "t": textField] label.setTranslatesAutoresizingMaskIntoConstraints(false) textField.setTranslatesAutoresizingMaskIntoConstraints(false) let c1 = NSLayoutConstraint.constraintsWithVisualFormat(“V:|-40-[l(32)]", options: nil, metrics: nil, views: dic) let c2 = NSLayoutConstraint.constraintsWithVisualFormat(“V:|-40-[t(32)]", options: nil, metrics: nil, views: dic) let c3 = NSLayoutConstraint.constraintsWithVisualFormat(“|-20-[l(==t)]-10-[t]-|", options: nil, metrics: nil, views: dic) self.view.addConstraints(c1) self.view.addConstraints(c2) self.view.addConstraints(c3)

Slide 9

Slide 9 text

yavfl: Yet Another VFL visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } ΍ Ϳ ; Δ

Slide 10

Slide 10 text

Visual Format Language yavfl visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } let dic = ["l": label, "t": textField] label.setTranslatesAutoresizingMaskIntoConstraints(false) textField.setTranslatesAutoresizingMaskIntoConstraints(false) let c1 = NSLayoutConstraint.constraintsWithVisualFormat(“V:|-40-[l(32)]", options: nil, metrics: nil, views: dic) let c2 = NSLayoutConstraint.constraintsWithVisualFormat(“V:|-40-[t(32)]", options: nil, metrics: nil, views: dic) let c3 = NSLayoutConstraint.constraintsWithVisualFormat(“|-20-[l(==t)]-10-[t]-|", options: nil, metrics: nil, views: dic) self.view.addConstraints(c1) self.view.addConstraints(c2) self.view.addConstraints(c3)

Slide 11

Slide 11 text

ಛ௃ • Visual Format Language෩ͷݴޠ • (VFLͷ) Predicate΍PriorityͳͲʹ΋ҰԠରԠ • ίϯύΠϧ࣌ʹνΣοΫ͞ΕΔͷͰ҆৺ • XcodeͰͷิ׬ • Mac, iOS྆ରԠ • CocoaPodsͰ؆୯ಋೖ • Swift 1.2ඇରԠ

Slide 12

Slide 12 text

yavfl.playground ༡ͼ৔׬උ

Slide 13

Slide 13 text

Inside yavfl

Slide 14

Slide 14 text

yavflͷॲཧ (֓ཁ) • SwiftͷݴޠػೳΛ͍Ζ͍Ζ࢖ͬͯɺ • Visual Format LanguageͷจࣈྻΛ࡞ͬͯɺ • NSLayoutConstraintͷ constraintsWithVisualFormat:options:metrics:views Λద༻͢Δ͚ͩ ςετ͕ɺZBWqͷදهˠ7'-ͷදهͷ ม׵͕ਖ਼͍͜͠ͱͷνΣοΫ͚ͩͰࡁΉ

Slide 15

Slide 15 text

yavflͰ࢖ͬͨSwiftͷݴޠػೳ • Trailing Closures • enum • Custom Operators • LiteralConvertible • Build Configurations

Slide 16

Slide 16 text

Trailing Closures

Slide 17

Slide 17 text

Trailing Closures ࠷ޙͷΫϩʔδϟ͕ؔ਺ͷׅހ֎ʹॻ͚Δ [1,2,3].map({ $0 * $0 }) [1,2,3].map { $0 * $0 }

Slide 18

Slide 18 text

Trailing Closures visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } func visualFormat(v1: UIView, v2: UIView, closure:(ViewExpression, ViewExpression) -> ())

Slide 19

Slide 19 text

visualFormat func visualFormat(v1: YAVView, v2: YAVView, closure: (ViewExpression, ViewExpression) -> ()) { v1.yav_setTranslatesAutoresizingMaskIntoConstraints(false) v2.yav_setTranslatesAutoresizingMaskIntoConstraints(false) closure(.View(LayoutViewName(v1, 1)), .View(LayoutViewName(v2, 2))) v1.updateConstraints() v2.updateConstraints() }

Slide 20

Slide 20 text

visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| }

Slide 21

Slide 21 text

visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } .H ~ |-20-[l,==t]-10-[t]-| enum

Slide 22

Slide 22 text

enum

Slide 23

Slide 23 text

enum enum LayoutOrientation : String { case V = "V" case H = "H" }

Slide 24

Slide 24 text

Associated Values enum Shape { case Circle(Int) case Rectangle(Int, Int) }

Slide 25

Slide 25 text

Visual Format String Grammarʹج͍ͮͨ஋Λఆٛ enum VisualFormat { case Superview case View(LayoutView) case Connection case Predicate(LayoutPredicate) case Number(Int) case Composition([VisualFormat]) case Options(NSLayoutFormatOptions) } | [l] - 20 ==t

Slide 26

Slide 26 text

LiteralConvertible

Slide 27

Slide 27 text

IntegerLiteralConvertible enum VisualFormat : IntegerLiteralConvertible { case Superview case View(LayoutView) case Connection case Predicate(LayoutPredicate) case Number(Int) case Composition([VisualFormat]) case Options(NSLayoutFormatOptions) } let vf: VisualFormat = 3 IntegerLiteralConvertible case Number(Int) public init(integerLiteral value: IntegerLiteralType) { self = .Number(value) } }

Slide 28

Slide 28 text

enum VisualFormat : IntegerLiteralConvertible, ArrayLiteralConvertible { case Superview case View(LayoutView) case Connection case Predicate(LayoutPredicate) case Number(Int) case Composition([VisualFormat]) case Options(NSLayoutFormatOptions) public init(integerLiteral value: IntegerLiteralType) { self = .Number(value) } public init(arrayLiteral elements: ViewExpression...) { self = .View(LayoutView(elements)) } } nshipster.com/swift-literal-convertible Swift Literal Convertibles let w1: ViewExpression = .View(LayoutViewName(v1, 1)) let w2: ViewExpression = .View(LayoutViewName(v2, 2)) let vf: VisualFormat = [w1,==w2]

Slide 29

Slide 29 text

visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } .H ~ |-20-[l,==t]-10-[t]-| (ArrayLiteralConvertible) VisualFormat (IntegerLiteralConvertible) VisualFormat LayoutOrientation

Slide 30

Slide 30 text

Custom Operators

Slide 31

Slide 31 text

Custom Operators • લஔ (prefix), ޙஔ (postfix), தஔ (infix) • ༏ઌॱҐ (precedence) • ݁߹ੑ (associativity) a + b * c a ~ (b ~ c) (a ~ b) ~ c a ~ b ~ c ++a a++ a + b a + (b * c) (a + b) * c

Slide 32

Slide 32 text

visualFormat(label, textField) { l, t in .V ~ |-40-[l,==32] .V ~ |-40-[t,==32] .H ~ |-20-[l,==t]-10-[t]-| } .H ~ |-20-[l,==t]-10-[t]-| prefix postfix infix

Slide 33

Slide 33 text

prefix operator |- {} public prefix func |- (e: VisualFormat) -> VisualFormat { return VisualFormat(composition: .Superview, .Connection, e) } .H ~ |-20-[l,==t]-10-[t]-| .Number(20)

Slide 34

Slide 34 text

.H ~ |-20-[l,==t]-10-[t]-| .H ~ |- - - - -| 20 l 10 t - | 20 - t | l 10 .H ~ - - - - | 20 - t | l 10 .H ~ - - - public func -(lhs: VisualFormat, rhs: VisualFormat) -> VisualFormat { return VisualFormat(composition: lhs, .Connection, rhs) }

Slide 35

Slide 35 text

.H ~ |-20-[l,==t]-10-[t]-| public func ~(lhs: LayoutOrientation, rhs: VisualFormat) -> [AnyObject] { if let superView = rhs.superView? { let exp = lhs.description + ":" + rhs.description let dic = rhs.viewsDictionary let opts = rhs.options let c = NSLayoutConstraint.constraintsWithVisualFormat(exp, options: opts, metrics: nil, views: dic) superView.addConstraints(c) return c } return [] } - | 20 - t | l 10 .H ~ - - - H:|-20-[l(==t)]-10-[t]-| ==t

Slide 36

Slide 36 text

Grammar of Operators (from Language Reference) operator → operator-head operator-characters opt operator → dot-operator-head dot-operator-characters opt operator-head → / | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | ? operator-head → U+00A1–U+00A7 operator-head → U+00A9 or U+00AB operator-head → U+00AC or U+00AE operator-head → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7 operator-head → U+2016–U+2017 or U+2020–U+2027 ɿ # $ @ : , ͳͲ͸࢖͑ͳ͍

Slide 37

Slide 37 text

mattt/Euler Swift Custom Operators for Mathematical Notation infix operator ∈ { associativity left } func ∈ (left: T, right: [T]) -> Bool { return contains(right, left) } print(2 ∈ [2,3,4]) // true print(1 ∈ [2,3,4]) // false

Slide 38

Slide 38 text

Build Configurations

Slide 39

Slide 39 text

Build Configurations CݴޠͷϚΫϩΈ͍ͨͳͷ SwiftͰϚΫϩͬΆ͍͜ͱΛ͢Δ yashigani.hatenablog.com/entry/macros-in-swift #if os(OSX) // OSXͰͷΈ΍Γ͍ͨॲཧ #endif

Slide 40

Slide 40 text

Build Configurations OSͷҧ͍Λٵऩ #if os(iOS) import UIKit public typealias YAVView = UIView #else import AppKit public typealias YAVView = NSView #endif extension YAVView { private func yav_setTranslatesAutoresizingMaskIntoConstraints(flag: Bool) { #if os(iOS) setTranslatesAutoresizingMaskIntoConstraints(flag) #else translatesAutoresizingMaskIntoConstraints = flag #endif } }

Slide 41

Slide 41 text

OTHER_SWIFT_FLAGS="-DCOCOAPODS" • CocoaPodsͰ͸Ϟδϡʔϧ໊͕ৗʹFoo • ඇCocoaPodsͰ͸ɺMac؀ڥͷΈFooOSXʹͳΔ #if os(iOS) || COCOAPODS import Foo #else import FooOSX #endif

Slide 42

Slide 42 text

·ͱΊ

Slide 43

Slide 43 text

·ͱΊ • Auto LayoutϥΠϒϥϦyavflͰ͸ɺ • Trailing ClosureͷதͰɺ • ArrayLiteralConvertibleͳͲͰద౰ͳenum஋ʹม͑ͭͭɺ • Custom OperatorͰͦΕΒΛ഑ྻʹ·ͱΊ͔ͯΒɺ • ͦΕΛจࣈྻʹม׵ͯ͠NSLayoutConstraint. constraintsWithVisualFormatΛ࢖ͬͯ·͢ɻ

Slide 44

Slide 44 text

Visual Format Language Ͱ͸ॻ͚ͳ͍΋ͷ΋͋Δ • ΞεϖΫτൺͷࢦఆͳͲ imageView.width = 2 * imageView.height “Auto Layout Guide” from Apple

Slide 45

Slide 45 text

ྨࣅϓϩδΣΫτ 0xc010d/VFLToolbox robb/Cartography ConstraintΛॻͨ͘ΊͷϥΠϒϥϦ matteocrippa/awesome-swift view.addConstraints(V:|-[view1]-4-[view2]-|) layout(view1, view2) { view1, view2 in view1.width == view1.superview!.width * 0.5 view2.width == view1.width - 50 }