Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Xcode Previews - IB없이 개발하기

VCNC
November 12, 2019

Xcode Previews - IB없이 개발하기

모바일 개발자에게 화면을 예쁘게 만드는 것은 매우 중요한 업무 중 하나이다. 하지만 이를 달성하기 위해서는 매번 구현, 빌드, 전달, 해당화면 띄우기 등 너무나 많은 시간과 노력이 요구된다. 그뿐만 아니라 잘 동작하는 앱을 만들기 위해서는 dynamic content size, 다크모드 등 다양한 환경과 여러 디바이스에서 확인해야 한다. 이러한 문제를 해결하기 위해 Xcode11에서 Previews 라는 기능이 추가되었다. 이번 세션에서는 Xcode Previews 에 대한 소개와 동작 원리를 파악하고 간단한 데모를 통해 해당 기능을 이해해보려고 한다. 더 나아가 SwiftUI 를 사용하지 않는 기존의 서비스에서 Previews 기능을 사용하는 방법을 알아보고, 이를 이용해 타다가 어떻게 UI 작업을 진행하는지 공유하고자 한다.

VCNC

November 12, 2019
Tweet

More Decks by VCNC

Other Decks in Programming

Transcript

  1. 7$/$
    ӣթഅ
    9DPEF1SFWJFXT
    ఋ׮о*#ܳߡܽ੉ਬ

    View full-size slide

  2. 7$/$
    ӣթഅ
    9DPEF1SFWJFXT
    ఋ׮о*#ܳߡܽ੉ਬ*#হ੉ѐߊೞӝ

    View full-size slide

  3. Xcode Previews

    Xcode Previews in UIKit

    Problems with Storyboard, XIB

    UI programming using Xcode Previews
    $POUFOUT

    View full-size slide

  4. Xcode Previews

    View full-size slide

  5. • Xcode 11

    • MacOS Catalina
    9DPEF1SFWJFXT

    View full-size slide

  6. #BDLHSPVOE
    `
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  7. #BDLHSPVOE
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  8. #BDLHSPVOE
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  9. • Configuring

    • Building

    • Running

    • Navigating

    • Getting to the state
    #BDLHSPVOE

    View full-size slide

  10. #BDLHSPVOE
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  11. #BDLHSPVOE
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  12. #BDLHSPVOE
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  13. Time consuming

    View full-size slide

  14. 9DPEF1SFWJFXT
    Mastering Xcode Previews @WWDC 2019

    View full-size slide

  15. struct PriceView_Preview: PreviewProvider {
    static var previews: some View {
    PriceView(price:…)
    .previewLayout(.sizeThatFits)
    .environment(\.colorScheme, .dark)
    }
    }

    View full-size slide

  16. Previews ز੘ ਗܻ

    View full-size slide

  17. • 2 Main Components

    • A preview build

    • Xcode extension ( live view )
    9DPEF1SFWJFXT

    View full-size slide

  18. • Normal Build

    • Xcode scheme, build settings ਸ ٮܰח ੌ߈੸ੋ ࠽٘

    • Preview Build

    • ୶о compile optionҗ ೣԋ normal buildܳ ഛ੢ೠ ߹ب੄
    ࠽٘

    9DPEF1SFWJFXT

    View full-size slide

  19. • Xcode build artifact ী normal ࠽٘৬ ೣԋ ઓ੤

    • Object file, artifact ҕਬ

    • Additional Options

    • Interactive UI ࣻ੿ / dynamic behavior ೲਊ

    • ਗࠄ ౵ੌ ৻ ୶о੸ੋ ࣗझ ౵ੌ ࢤࢿ

    • ਗࠄ ࣗझ ௏٘ܳ ࠗ࠙੸ਵ۽ UIܳ ࣻ੿ೡ ࣻ ੓ח ௏٘۽ ߸҃
    by method swizzling
    1SFWJFX#VJME

    View full-size slide

  20. 1SFWJFX#VJME

    View full-size slide

  21. struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
    ContentView()
    }
    }

    View full-size slide

  22. @_private(sourceFile: "ContentView.swift") import LetSwiftPreview
    import SwiftUI
    import SwiftUI
    extension ContentView_Previews {
    @_dynamicReplacement(for: previews) private static var
    __preview__previews: some View {
    #sourceLocation(file: "/Users/nate/Documents/samples/SwiftUI/
    LetSwiftPreview/LetSwiftPreview/LetSwiftPreview/ContentView.swift", line: 19)
    AnyView(__designTimeSelection(ContentView(), "#40077.[2].[0].property.[0].
    [0]"))
    #sourceLocation()
    }
    }
    typealias ContentView = LetSwiftPreview.ContentView
    typealias ContentView_Previews = LetSwiftPreview.ContentView_Previews

    View full-size slide

  23. • Xcodeо пࢤࢿػ ౵ੌਸ ة݀੸ੋ dynamic
    library۽ ࠽٘

    • library -> Preview applicationਵ۽ ۽٘
    9DPEF1SFWJFXT

    View full-size slide

  24. Xcode Previews

    in UIKit

    View full-size slide

  25. • UIViewController ب Previews ࢎਊ оמ

    • UIViewControllerRepresentable protocol
    9DPEF1SFWJFXTJO6*,JU
    func makeUIViewController(context: Self.Context)
    -> Self.UIViewControllerType
    func updateUIViewController(
    _ uiViewController: Self.UIViewControllerType,
    context: Self.Context
    )

    View full-size slide

  26. • UIView ب Previews ࢎਊ оמ

    • UIViewRepresentable protocol
    9DPEF1SFWJFXTJO6*,JU
    func makeUIView(context: Self.Context)
    -> Self.UIViewType
    func updateUIView(
    _ uiView: Self.UIViewType, context: Self.Context
    )

    View full-size slide

  27. • Previews ীࢲ ࢎਊೞӝ ਤೠ protocol

    • UIKit -> SwiftUI

    • SwiftUI ܳ ࢎਊೡ ࣻ ੓ח ജ҃ীࢲ݅ ੉ਊ оמ
    6*7JFX3FQSFTFOUBCMF

    View full-size slide

  28. • Debug ࠽٘ ࢸ੿ ߸҃

    • iOS Deployment target : iOS13

    • canImport, @available
    9DPEF1SFWJFXTJ04

    View full-size slide

  29. #if canImport(SwiftUI) && DEBUG
    import SwiftUI
    @available(iOS 13.0, *)
    struct PriceView_Preview: UIViewRepresentable,
    PreviewProvider {
    let price: Price
    func makeUIView(context: Self.Context) -> PriceView {
    PriceView().also { $0.price = price }
    }
    func updateUIView(_ view: PriceView,
    context: Self.Context) {

    }
    static var previews: some View {
    PriceView_Preview(price: …)
    }
    }
    #endif

    View full-size slide

  30. Problems with
    Storyboard, XIB

    View full-size slide

  31. • XML

    • ੍Ѣա ࣻ੿ೡ ࣻ হח XML

    • ࣻ ߔ઴ ੉࢚੄ ௾ ౵ੌ
    3FBEBCJMJUZ

    View full-size slide

  32. • XML

    • ੍Ѣա ࣻ੿ೡ ࣻ হח XML

    • ࣻ ߔ઴ ੉࢚੄ ௾ ౵ੌ

    • э਷ Viewܳ ࣻ੿ೞݶ?

    • PR
    3FBEBCJMJUZ

    View full-size slide

  33. • ౵ੌ੉ ੼੼ ழ૗

    • যו࢜ ࣻभ ѐ੄ झ௼ܽ੉ ೞա੄ ౵ੌী..

    • Source control ߄Ե ٸ݃׮
    4UPSZCPBSET

    View full-size slide

  34. • IBח Swift ௏٘ܳ ੜ ݽܴ(vice versa)

    • IBOutlet, IBAction ਸ ా೧ োѾ

    • IBীࢲ Viewܳ ૑ਕب ௏٘ח Ӓ؀۽…

    • Cell in TableView ীࢲ identifier۽ оઉয়ӝ
    (Typecast ೙ࣻ )
    4XJGU*OUFSGBDFCVJMEFS

    View full-size slide

  35. • Color asset ਵ۽ ࢸ੿ೠ ࢝੉ viewDidLoad,
    viewWillAppear, awakeFromNib ࣻ੿ ࠛо

    • Callstack

    • viewDidLoad(viewWillAppear) ->
    traitCollectionDidChanged ->

    ੿੄ػ asset color۽ trait collection ੸ਊ
    *OUFSGBDFCVJMEFSCVHT

    View full-size slide

  36. UI programming

    using Xcode Previews

    View full-size slide

  37. • Visualization

    • Image > Text

    • Views, Constraints ҳઑ ౵ঈ
    1SPHSBNNBUJDBMMZ6*

    View full-size slide

  38. • Verbose

    • Complex

    • Difficult to read
    1SPHSBNNBUJDBMMZ6*

    View full-size slide

  39. header.translatesAutoresizingMaskIntoConstraints = false
    let cn1 = NSLayoutConstraint(item: header,
    attribute: .leading, relatedBy: .equal, toItem: view,
    attribute: .leading, multiplier: 1.0, constant: 20)
    let cn2 = NSLayoutConstraint(item: header,
    attribute: .trailing, relatedBy: .equal, toItem: view,
    attribute: .trailing, multiplier: 1.0, constant: -20)
    let cn3 = NSLayoutConstraint(item: header,
    attribute: .height, relatedBy: .equal, toItem: nil,
    attribute: .notAnAttribute, multiplier: 1.0, constant: 60)
    let cn4 = NSLayoutConstraint(item: header, attribute: .top,
    relatedBy: .equal, toItem: view, attribute: .top,
    multiplier: 1.0, constant: 20)
    view.addConstraints([cn1, cn2, cn3, cn4])

    View full-size slide

  40. • Layout libraries

    • PureLayout, Cartogrphy, Snapkit …
    1SPHSBNNBUJDBMMZ6*

    View full-size slide

  41. header.snp.makeConstraints { maker in
    maker.leading.trailing.top.equalToSuperview().inset(20)
    maker.height.equalTo(60)
    }

    View full-size slide

  42. • ૒ҙ੸ਵ۽ ചݶਸ ੉೧ೞӝ য۰਑
    1SPHSBNNBUJDBMMZ6*

    View full-size slide

  43. blackView.snp.makeConstraints { make in
    make.center.equalTo(view)
    make.size.equalTo(CGSize(width: 100, height: 100))
    }
    redView.snp.makeConstraints { make in
    make.top.equalTo(blackView.snp.bottom).offset(20.0)
    make.right.equalTo(blackView.snp.left).offset(-20.0)
    make.size.equalTo(CGSize(width: 100, height: 100))
    }
    yellowView.snp.makeConstraints { make in
    make.top.equalTo(blackView.snp.bottom).offset(20.0)
    make.left.equalTo(blackView.snp.right).offset(20.0)
    make.size.equalTo(CGSize(width: 100, height: 100))
    }
    blueView.snp.makeConstraints { make in
    make.bottom.equalTo(blackView.snp.top).offset(-20.0)
    make.left.equalTo(blackView.snp.right).offset(20.0)
    make.size.equalTo(CGSize(width: 100, height: 100))
    }
    greenView.snp.makeConstraints { make in
    make.bottom.equalTo(blackView.snp.top).offset(-20.0)
    make.right.equalTo(blackView.snp.left).offset(-20.0)
    make.size.equalTo(CGSize(width: 100, height: 100))

    View full-size slide

  44. • ૒ҙ੸ਵ۽ ചݶਸ ੉೧ೞӝ য۰਑

    • View ҳઑܳ ౵ঈೞӝ ਤ೧ ੹୓ ௏٘ ౵ঈ ೙ਃ

    • View Hierarchy ↑ ➡ Time ↑

    • Layout library੄ ೠ҅
    1SPHSBNNBUJDBMMZ6*

    View full-size slide

  45. • makeConstraints: э਷ ࠗݽܳ ыח Views݅ оמ

    • addSubview / makeConstraints ௏٘ ܻ࠙

    • Nested ҳઑੌ ٸ children ਸ ݢ੷ ੘ࢿ
    4OBQ,JU

    View full-size slide

  46. IBKit

    https://github.com/glwithu06/IBKit

    View full-size slide

  47. • Visualization

    • ૒ҙ੸ੋ ௏٘ ੉೧

    *#,JU

    View full-size slide

  48. • Visualization -> Xcode Previews

    • ૒ҙ੸ੋ ௏٘ ੉೧ -> Declarative झఋੌ

    *#,JU

    View full-size slide

  49. UIView() {
    UIView().identifier(“upper")
    .backgroundColor(.cyan)
    .makeConstraints {
    $0.top.left.right.equalToSuperview()
    $0.height.equalTo(30)
    }
    UIView().identifier("lower")
    .backgroundColor(.blue)
    .makeConstraints {
    $0.top.equalTo($0.views.upper.bottom)
    $0.bottom.left.right.equalToSuperview()
    $0.height.equalTo(30)
    }
    }
    .identifier(“yellow")
    .assign(to: \.container, on: self)

    View full-size slide

  50. • UIViewRepresentable

    • UIViewControllerRepresentable

    • Preview(root:)
    9DPEF1SFWJFXT

    View full-size slide

  51. Preview sample

    View full-size slide

  52. • @_functionBuilder

    • Swift5.1 private feature
    %FDMBSBUJWFTUZMF

    View full-size slide

  53. @_functionBuilder struct ViewBulder {
    static func buildBlock() -> Builder {
    BuilderImpl(children: [])
    }
    static func buildEither(first: UIView) -> Builder {
    BuilderImpl(children: [first])
    }
    static func buildEither(second: UIView) -> Builder {
    BuilderImpl(children: [second])
    }
    static func buildIf(_ view: UIView?) -> Builder {
    BuilderImpl(children: view.map { [$0] } ?? [])
    }
    static func buildBlock(_ views: UIView...) -> Builder {
    BuilderImpl(children: views)
    }

    }

    View full-size slide

  54. • SnapKit ӝ߈ Layout

    • addSubview -> SnapKit.makeConstraints

    • Dynamic member lookup
    -BZPVU
    func makeConstraints(_ closure:
    @escaping (ConstraintMaker) -> Void) -> Self

    View full-size slide

  55. .makeConstraints {
    $0.left.right.equalToSuperview().inset(50)
    $0.top.equalTo($0.views.description.bottom).offset(30)
    $0.height.equalTo(30).priority(ConstraintPriority.low)
    }

    View full-size slide

  56. • KeyPath Binding
    "TTJHOWJFXT
    func assign(
    to keyPath: ReferenceWritableKeyPath,
    on object: Root
    ) -> Self

    View full-size slide

  57. • PreviewProvider protocol

    • Group / ForEach

    • previewLayout / previewDevice / environment

    • Development Assets

    • Pinning
    9DPEF1SFWJFXT

    View full-size slide

  58. • Preview Build

    • Derived source code

    • Preview library
    9DPEF1SFWJFXT

    View full-size slide

  59. • UIViewControllerRepresentable

    • UIViewRepresentable

    • makeUIView / updateUIView
    • canImport(SwiftUI)
    9DPEF1SFWJFXTJO6*,JU

    View full-size slide

  60. • Readability

    • Maintenance (Storyboard)

    • Swift <-> Interface Builder

    • Interface Builder bugs
    4UPSZ#PBSE 9*#

    View full-size slide

  61. • Visualization

    • Intuitive

    • IBKit
    1SPHSBNNBUJDBMMZ6*

    View full-size slide