Slide 1

Slide 1 text

! with IB AKIBA.swift × Τ΢ϨΧ ίʔυϨΠΞ΢τษڧձ 1

Slide 2

Slide 2 text

Who is me? Kazuya Ueoka iOS application engineer in Timers inc. Twitter: @fromkk Github: fromkk Qiita: fromkk 2

Slide 3

Slide 3 text

Interface Builder͋Δ͋Δ 3

Slide 4

Slide 4 text

Q. IBͷϑΝΠϧͱίʔυ͕ผʑͷσΟϨΫτϦʹ͍Δʁ 4

Slide 5

Slide 5 text

A. ಉ͡σΟϨΫτϦʹอଘ͠·͠ΐ͏ 5

Slide 6

Slide 6 text

Q. IB্Ͱमਖ਼ͨ͠͸ͣͳͷʹมߋ͕൓ө͞Εͳ͍? 6

Slide 7

Slide 7 text

A. IBͷϑΝΠϧΛमਖ਼͢ΔͷΛ΍Ί·͠ΐ͏ جຊతʹίʔυͷมߋ͕ޙউͪ 7

Slide 8

Slide 8 text

Q. IBOutlet࡟আͯ͠͠·ͬͯམͪͨࣄແ͍ʁ *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key sampleLabel. 8

Slide 9

Slide 9 text

A. IB͔Β֬ೝग़དྷΔ • ! ʹͳͬͯΔ࣌͸ඥ෇͚͕͏·͍ͬͯ͘ͳ͍ • ϑΝΠϧͷ؅ཧ͕2Օॴʹͳͬͯ͠·͏ͷେม 9

Slide 10

Slide 10 text

Q. Πϯελϯε࡞Δ࣌ʹinitͨ͠Βམͪͨࣄແ͍ʁ 10

Slide 11

Slide 11 text

A. Extension࡞ͬͯ๷͙ import UIKit protocol NibInstantiatable: class { static var nibName: String { get } } extension NibInstantiatable where Self: UIView { static func instantiate(bundle: Bundle = Bundle.main, owner: Any? = nil, options: [AnyHashable: Any]? = nil) -> Self { return UINib(nibName: Self.nibName, bundle: bundle).instantiate(withOwner: owner, options: options).first as! Self } } protocol StoryboardInstantiatable: class { static var storyboardName: String { get } static var storyboardIdentifier: String { get } } extension StoryboardInstantiatable where Self: UIViewController { static func instantiate(bundle: Bundle = Bundle.main, identifier: String) -> Self { return UIStoryboard(name: Self.storyboardName, bundle: bundle).instantiateViewController(withIdentifier: Self.storyboardIdentifier) as! Self } } 11

Slide 12

Slide 12 text

Usage class HogeView: UIView, NibInstantiatable { static var nibName: String { return "nibName" } } let hogeView = HogeView.instantiate() 12

Slide 13

Slide 13 text

Q. IBϑΝΠϧͷϩʔΧϥΠζ໘౗ष͘ͳ͍ʁ 13

Slide 14

Slide 14 text

A. ຋༁ʹؔ͢Δࣄ͸Localizable.stringʹू໿ ࣗવͱ຋༁͸ίʔυͰରԠ͢Δࣄʹ @IBOutlet weak var sampleLabel: UILabel! { didSet { sampleLabel.text = NSLocalizedString("sample.label.text", comment: "ϥϕϧ") } } 14

Slide 15

Slide 15 text

Q. ৭΍ϑΥϯτΛڞ௨Ͱ؅ཧग़དྷͳ͍ 15

Slide 16

Slide 16 text

A. ίʔυͰ·ͱΊ͓͖ͯ·͠ΐ͏ • ਖ਼֬ʹ͸৭ʹؔͯ͠͸Xcode 9/iOS 11͔ΒColor Asset ͸ར༻Մೳʹͳͬͨ • ԼҐޓ׵ੑΛߟ͑Δͱ·ͩ࢖͑ͳ͍ 16

Slide 17

Slide 17 text

৭ΛίʔυͰ؅ཧ͢Δ extension UIColor { struct MyColor { static let theme: UIColor = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1) static let action: UIColor = #colorLiteral(red: 0.4, green: 0.4, blue: 0.4, alpha: 1) static let backgroundColor: UIColor = #colorLiteral(red: 0.8, green: 0.8, blue: 0.8, alpha: 1) . . . } } 17

Slide 18

Slide 18 text

ϑΥϯτΛίʔυͰ؅ཧ͢Δ extension UIFont { struct MyFont { private static func font(with name: String, size: CGFloat) -> UIFont { let font = UIFont(name: name, size: size)! guard #available(iOS 11.0, *) else { return font } return UIFontMetrics.default.scaledFont(for: font) } private static func normal(with size: CGFloat) -> UIFont { return font(with: "Awesome-Font", size: size) } private static func bold(with size: CGFloat) -> UIFont { return font(with: "Awesome-Font-Bold", size: size) } static let largeTitle: UIFont = MyFont.normal(with: 34.0) static let title1: UIFont = MyFont.normal(with: 28.0) static let title2: UIFont = MyFont.normal(with: 22.0) static let title3: UIFont = MyFont.normal(with: 20.0) static let headline: UIFont = MyFont.bold(with: 17.0) static let body: UIFont = MyFont.normal(with: 17.0) static let callout: UIFont = MyFont.normal(with: 16.0) static let subheadline: UIFont = MyFont.normal(with: 15.0) static let footnote: UIFont = MyFont.normal(with: 13.0) static let caption1: UIFont = MyFont.normal(with: 12.0) static let caption2: UIFont = MyFont.normal(with: 11.0) } } 18

Slide 19

Slide 19 text

ଞʹ΋ • ϑΝΠϧΛ։͍͚ͨͩͰDiff͕ൃੜͯ͠͠·͏ • PRͷ࣌ʹϨϏϡʔ͕೉͍͠ • Ϗϧυͯ͠ΈΔͱ৭͕ҧ͏ • etc... 19

Slide 20

Slide 20 text

Q. ن໿(ϧʔϧ)Ͱ๷͛͹͍͍ʁ 20

Slide 21

Slide 21 text

A. ͦ΋ͦ΋ϧʔϧ͸গͳ͍ํ͕ྑ͍ 21

Slide 22

Slide 22 text

ϧʔϧ͸ഁΒΕΔҝʹ͋Δ • ਓ͕ൈ͚ͨΓೖͬͨΓͯ͠΋อͯΔʁ • IBͰ͸AutoLayoutͷઃఆ͔͠͠ͳ͍ʁ • ϥϕϧͷ৭΍ϑΥϯτ͸ίʔυͰઃఆ͢ΔʁIBͷํָ͕͡Ό ͳ͍ʁ • ͦͷ࣌ʑͰָͳํ๏ΛબΜͩΓͯ͠ͳ͍ʁ 22

Slide 23

Slide 23 text

IB͑͞࢖Θͳ͚Ε͹ߟ͑ΔࣄݮΔͷͰ͸ 23

Slide 24

Slide 24 text

Interface BuilderࣺͯΑ͏ 24

Slide 25

Slide 25 text

1. AutoLayoutΛίʔυͰॻ͘ let sampleLabel = UILabel() sampleLabel.translatesAutoresizingMaskIntoConstraints = false view.addSubview(sampleLabel) NSLayoutConstraint.activate([ sampleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0), sampleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0), view.trailingAnchor.constraint(equalTo: sampleLabel.trailingAnchor, constant: 16.0), view.bottomAnchor.constraint(equalTo: sampleLabel.bottomAnchor, constant: 8.0) ]) 25

Slide 26

Slide 26 text

σϝϦοτ΋͋Δ 26

Slide 27

Slide 27 text

Q.translatesAutoresizingMaskIntoConstraints Λॻ͖๨ΕΔ 27

Slide 28

Slide 28 text

A. ബ͍ϥούʔ࡞Ζ͏ // ఆٛ extension UIView { func addSubview(_ view: UIView, with layouts: (UIView) -> ([NSLayoutConstraint])) { view.translatesAutoresizingMaskIntoConstraints = false addSubview(view) NSLayoutConstraint.activate(layouts(view)) } } // ࢖༻ addSubview(sampleLabel) { label -> [NSLayoutConstraint] in [ label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0), label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0), trailingAnchor.constraint(equalTo: label.trailingAnchor, constant: 16.0), bottomAnchor.constraint(equalTo: label.bottomAnchor, constant: 8.0) ] } 28

Slide 29

Slide 29 text

Q. SafeAreaਏ͍ let top: NSLayoutConstraint if #available(iOS 11.0, *) { top = button.topAnchor.constraint(equalTop: view.safeAreaLayoutGuide.topAnchor, constant: 16.0) } else { top = button.topAnchor.constraint(equalTop: view.topAnchor, constant: 16.0) } NSLayoutConstraint.activate([ top, button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0), button.widthAnchor.constraint(equalToConstant: 200.0), button.heightAnchor.constraint(equalToConstant: 48.0), ]) 29

Slide 30

Slide 30 text

A. ബ͍ϥούʔ࡞Ζ͏ extension UIView { struct MySafeAreaLayoutGuide { weak var view: UIView! var topAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return view.safeAreaLayoutGuide.topAnchor } else { return view.topAnchor } } var bottomAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return view.safeAreaLayoutGuide.bottomAnchor } else { return view.bottomAnchor } } . . . } var myLayoutGuide: MySafeAreaLayoutGuide { return MySafeAreaLayoutGuide(view: self) } } 30

Slide 31

Slide 31 text

Usage NSLayoutConstraint.activate([ button.topAnchor.constraint(equalTo: view.myLayoutGuide.topAnchor), . . . ]) iOS 11ະຬΛ੾Δ࣌ʹ myLayoutGuide Λ safeAreaLayoutGuide ʹஔ׵͢Δ͚ͩͰࡁΉͷͰָ 31

Slide 32

Slide 32 text

Q. ϨΠΞ΢τΛίʔυͰॻ͍͍ͯΔͱ Ͳͷը໘͔Θ͔Βͳ͘ͳͬͯ͠·͏໰୊ 32

Slide 33

Slide 33 text

A. ίʔυʹը໘֓ཁਤ৐ͤͯ͠·͏ 33

Slide 34

Slide 34 text

Diff΋෼͔Γ΍͍͢ 34

Slide 35

Slide 35 text

·ͱΊ 1.ϧʔϧΛݮΒ͢ҝʹIB͸ࣺͯͯ͠·͍·͠ΐ͏ 2.AutoLayout͸ബ͍ϥούʔΛ࡞ͬͯίʔυͰॻ͘ 3.Ͳͷը໘͔෼͔ΓͮΒ͘ͳΔ࣌͸ίϝϯτΛۦ࢖͢Δ 35

Slide 36

Slide 36 text

PR 1 36

Slide 37

Slide 37 text

37

Slide 38

Slide 38 text

38

Slide 39

Slide 39 text

39

Slide 40

Slide 40 text

PR 2 40

Slide 41

Slide 41 text

https://pre-wwdc.connpass.com/event/83343/ 41

Slide 42

Slide 42 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ 42