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 ఋ׮о*#ܳߡܽ੉ਬ

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

  3. Xcode Previews Xcode Previews in UIKit Problems with Storyboard, XIB

    UI programming using Xcode Previews $POUFOUT
  4. Xcode Previews

  5. • Xcode 11 • MacOS Catalina 9DPEF1SFWJFXT

  6. #BDLHSPVOE ` Mastering Xcode Previews @WWDC 2019

  7. #BDLHSPVOE Mastering Xcode Previews @WWDC 2019

  8. #BDLHSPVOE Mastering Xcode Previews @WWDC 2019

  9. • Configuring • Building • Running • Navigating • Getting

    to the state #BDLHSPVOE
  10. #BDLHSPVOE Mastering Xcode Previews @WWDC 2019

  11. #BDLHSPVOE Mastering Xcode Previews @WWDC 2019

  12. #BDLHSPVOE Mastering Xcode Previews @WWDC 2019

  13. Time consuming

  14. 9DPEF1SFWJFXT Mastering Xcode Previews @WWDC 2019

  15. struct PriceView_Preview: PreviewProvider { static var previews: some View {

    PriceView(price:…) .previewLayout(.sizeThatFits) .environment(\.colorScheme, .dark) } }
  16. 4BNQMF

  17. Demo

  18. Previews ز੘ ਗܻ

  19. • 2 Main Components • A preview build • Xcode

    extension ( live view ) 9DPEF1SFWJFXT
  20. • Normal Build • Xcode scheme, build settings ਸ ٮܰח

    ੌ߈੸ੋ ࠽٘ • Preview Build • ୶о compile optionҗ ೣԋ normal buildܳ ഛ੢ೠ ߹ب੄ ࠽٘ 9DPEF1SFWJFXT
  21. • Xcode build artifact ী normal ࠽٘৬ ೣԋ ઓ੤ •

    Object file, artifact ҕਬ • Additional Options • Interactive UI ࣻ੿ / dynamic behavior ೲਊ • ਗࠄ ౵ੌ ৻ ୶о੸ੋ ࣗझ ౵ੌ ࢤࢿ • ਗࠄ ࣗझ ௏٘ܳ ࠗ࠙੸ਵ۽ UIܳ ࣻ੿ೡ ࣻ ੓ח ௏٘۽ ߸҃ by method swizzling 1SFWJFX#VJME
  22. 1SFWJFX#VJME

  23. struct ContentView_Previews: PreviewProvider { static var previews: some View {

    ContentView() } }
  24. @_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
  25. • Xcodeо пࢤࢿػ ౵ੌਸ ة݀੸ੋ dynamic library۽ ࠽٘ • library

    -> Preview applicationਵ۽ ۽٘ 9DPEF1SFWJFXT
  26. Xcode Previews in UIKit

  27. • UIViewController ب Previews ࢎਊ оמ • UIViewControllerRepresentable protocol 9DPEF1SFWJFXTJO6*,JU

    func makeUIViewController(context: Self.Context) -> Self.UIViewControllerType func updateUIViewController( _ uiViewController: Self.UIViewControllerType, context: Self.Context )
  28. • UIView ب Previews ࢎਊ оמ • UIViewRepresentable protocol 9DPEF1SFWJFXTJO6*,JU

    func makeUIView(context: Self.Context) -> Self.UIViewType func updateUIView( _ uiView: Self.UIViewType, context: Self.Context )
  29. • Previews ীࢲ ࢎਊೞӝ ਤೠ protocol • UIKit -> SwiftUI

    • SwiftUI ܳ ࢎਊೡ ࣻ ੓ח ജ҃ীࢲ݅ ੉ਊ оמ 6*7JFX3FQSFTFOUBCMF
  30. • Debug ࠽٘ ࢸ੿ ߸҃ • iOS Deployment target :

    iOS13 • canImport, @available 9DPEF1SFWJFXTJ04
  31. #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
  32. Demo

  33. Problems with Storyboard, XIB

  34. • XML • ੍Ѣա ࣻ੿ೡ ࣻ হח XML • ࣻ

    ߔ઴ ੉࢚੄ ௾ ౵ੌ 3FBEBCJMJUZ
  35. 3FBEBCJMJUZ

  36. • XML • ੍Ѣա ࣻ੿ೡ ࣻ হח XML • ࣻ

    ߔ઴ ੉࢚੄ ௾ ౵ੌ • э਷ Viewܳ ࣻ੿ೞݶ? • PR 3FBEBCJMJUZ
  37. None
  38. • ౵ੌ੉ ੼੼ ழ૗ • যו࢜ ࣻभ ѐ੄ झ௼ܽ੉ ೞա੄

    ౵ੌী.. • Source control ߄Ե ٸ݃׮ 4UPSZCPBSET
  39. • IBח Swift ௏٘ܳ ੜ ݽܴ(vice versa) • IBOutlet, IBAction

    ਸ ా೧ োѾ • IBীࢲ Viewܳ ૑ਕب ௏٘ח Ӓ؀۽… • Cell in TableView ীࢲ identifier۽ оઉয়ӝ (Typecast ೙ࣻ ) 4XJGU*OUFSGBDFCVJMEFS
  40. • Color asset ਵ۽ ࢸ੿ೠ ࢝੉ viewDidLoad, viewWillAppear, awakeFromNib ࣻ੿

    ࠛо • Callstack • viewDidLoad(viewWillAppear) -> traitCollectionDidChanged ->
 ੿੄ػ asset color۽ trait collection ੸ਊ *OUFSGBDFCVJMEFSCVHT
  41. UI programming using Xcode Previews

  42. • Visualization • Image > Text • Views, Constraints ҳઑ

    ౵ঈ 1SPHSBNNBUJDBMMZ6*
  43. • Verbose • Complex • Difficult to read 1SPHSBNNBUJDBMMZ6*

  44. 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])
  45. • Layout libraries • PureLayout, Cartogrphy, Snapkit … 1SPHSBNNBUJDBMMZ6*

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

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

  48. 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))
  49. • ૒ҙ੸ਵ۽ ചݶਸ ੉೧ೞӝ য۰਑ • View ҳઑܳ ౵ঈೞӝ ਤ೧

    ੹୓ ௏٘ ౵ঈ ೙ਃ • View Hierarchy ↑ ➡ Time ↑ • Layout library੄ ೠ҅ 1SPHSBNNBUJDBMMZ6*
  50. • makeConstraints: э਷ ࠗݽܳ ыח Views݅ оמ • addSubview /

    makeConstraints ௏٘ ܻ࠙ • Nested ҳઑੌ ٸ children ਸ ݢ੷ ੘ࢿ 4OBQ,JU
  51. IBKit https://github.com/glwithu06/IBKit

  52. • Visualization • ૒ҙ੸ੋ ௏٘ ੉೧ *#,JU

  53. • Visualization -> Xcode Previews • ૒ҙ੸ੋ ௏٘ ੉೧ ->

    Declarative झఋੌ *#,JU
  54. 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)
  55. Demo

  56. • UIViewRepresentable • UIViewControllerRepresentable • Preview(root:) 9DPEF1SFWJFXT

  57. Preview sample

  58. • @_functionBuilder • Swift5.1 private feature %FDMBSBUJWFTUZMF

  59. @_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) } … }
  60. • SnapKit ӝ߈ Layout
 • addSubview -> SnapKit.makeConstraints • Dynamic

    member lookup -BZPVU func makeConstraints(_ closure: @escaping (ConstraintMaker) -> Void) -> Self
  61. .makeConstraints { $0.left.right.equalToSuperview().inset(50) $0.top.equalTo($0.views.description.bottom).offset(30) $0.height.equalTo(30).priority(ConstraintPriority.low) }

  62. • KeyPath Binding "TTJHOWJFXT func assign<Root>( to keyPath: ReferenceWritableKeyPath<Root, Self>,

    on object: Root ) -> Self
  63. Wrap up

  64. • PreviewProvider protocol • Group / ForEach • previewLayout /

    previewDevice / environment • Development Assets • Pinning 9DPEF1SFWJFXT
  65. • Preview Build • Derived source code • Preview library

    9DPEF1SFWJFXT
  66. • UIViewControllerRepresentable • UIViewRepresentable • makeUIView / updateUIView • canImport(SwiftUI)

    9DPEF1SFWJFXTJO6*,JU
  67. • Readability • Maintenance (Storyboard) • Swift <-> Interface Builder

    • Interface Builder bugs 4UPSZ#PBSE 9*#
  68. • Visualization • Intuitive • IBKit 1SPHSBNNBUJDBMMZ6*

  69. 8FsSFIJSJOH

  70. None