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

先週解決した SwiftUI 問題

先週解決した SwiftUI 問題

2021/01/29 Swift 愛好会での発表スライドです。

2028fcf9065b3e34d2732587b6ac7bc5?s=128

Megabits_mzq

January 29, 2021
Tweet

More Decks by Megabits_mzq

Other Decks in Programming

Transcript

  1. デーモンコアくんって何? 先週解決した SwiftUI 問題 It’s me! @Megabits_mzq!

  2. None
  3. None
  4. None
  5. struct aView: View { @State var isShowingAlert = false var

    body: some View { ZStack { if isShowingAlert { PopoutAlertView( title: "Reset", content: "Really want to reset?", onTapButtonCancel: { isShowingAlert = false }, onTapButtonOk: { // ...... isShowingAlert = false }) } // ...... } } }
  6. アラート View コントローラー @Binding @Binding @Binding @State

  7. アラート View コントローラー Noti f i cation

  8. var resetButton: some View { Button(action: { isShowingAlert = true

    }, label: { sideViewButton(imageName: "arrow") }) .fullScreenCover(isPresented: $isShowingAlert, content: { PopoutAlertView( title: "Reset", content: "Really want to reset?", onTapButtonCancel: { isShowingAlert = false }, onTapButtonOk: { currentBrain.reset() isShowingAlert = false }) }) }
  9. None
  10. None
  11. var uiHost: UIHostingController<PopoutAlertView>! let alertView = PopoutAlertView( title: "Reset conform",

    contents: "Reset conform message”, onTapButtonCancel: { uiHost.dismiss(animated: false, completion: nil) }, onTapButtonOk: { uiHost.dismiss(animated: false, completion: nil) ...... }) uiHost = UIHostingController(rootView: alertView) uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = .clear present(uiHost, animated: false, completion: nil)
  12. var resetButton: some View { Button(action: { isShowingAlert = true

    }, label: { sideViewButton(imageName: "arrow.triangle.2.circlepath") }).overCurrentContext(isPresented: $isShowingAlert, content: { return AnyView ( PopoutAlertView( title: "Reset board", content: "Really want to reset board?", onTapButtonCancel: { isShowingAlert = false }, onTapButtonOk: { currentBrain.reset() isShowingAlert = false }) ) }) }
  13. import UIKit import SwiftUI fileprivate var currentOverCurrentContextUIHost: UIHostingController<AnyView>? = nil

    extension View { public func overCurrentContext( isPresented: Binding<Bool>, afterDismiss: (() -> Void)? = nil, content: () -> AnyView ) -> some View { if isPresented.wrappedValue && currentOverCurrentContextUIHost == nil { let uiHost = UIHostingController(rootView: content()) currentOverCurrentContextUIHost = uiHost uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = UIColor.clear let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.present(uiHost, animated: false, completion: nil) } else { if let uiHost = currentOverCurrentContextUIHost { uiHost.dismiss(animated: false, completion: {}) currentOverCurrentContextUIHost = nil afterDismiss?() } } return self } }
  14. import UIKit import SwiftUI fileprivate var currentOverCurrentContextUIHost: UIHostingController<AnyView>? = nil

    extension View { public func overCurrentContext( isPresented: Binding<Bool>, afterDismiss: (() -> Void)? = nil, content: () -> AnyView ) -> some View { if isPresented.wrappedValue && currentOverCurrentContextUIHost == nil { let uiHost = UIHostingController(rootView: content()) currentOverCurrentContextUIHost = uiHost uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = UIColor.clear let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.present(uiHost, animated: false, completion: nil) } else { if let uiHost = currentOverCurrentContextUIHost {
  15. import UIKit import SwiftUI fileprivate var currentOverCurrentContextUIHost: UIHostingController<AnyView>? = nil

    extension View { public func overCurrentContext( isPresented: Binding<Bool>, afterDismiss: (() -> Void)? = nil, content: () -> AnyView ) -> some View { if isPresented.wrappedValue && currentOverCurrentContextUIHost == nil { let uiHost = UIHostingController(rootView: content()) currentOverCurrentContextUIHost = uiHost uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = UIColor.clear let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.present(uiHost, animated: false, completion: nil) } else { if let uiHost = currentOverCurrentContextUIHost {
  16. import UIKit import SwiftUI fileprivate var currentOverCurrentContextUIHost: UIHostingController<AnyView>? = nil

    extension View { public func overCurrentContext( isPresented: Binding<Bool>, afterDismiss: (() -> Void)? = nil, content: () -> AnyView ) -> some View { if isPresented.wrappedValue && currentOverCurrentContextUIHost == nil { let uiHost = UIHostingController(rootView: content()) currentOverCurrentContextUIHost = uiHost uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = UIColor.clear let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.present(uiHost, animated: false, completion: nil) } else { if let uiHost = currentOverCurrentContextUIHost { public func fullScreenCover<Content>(isPresented: Binding<Bool>, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Content) -> some View where Content : View
  17. var resetButton: some View { Button(action: { isShowingAlert = true

    }, label: { sideViewButton(imageName: "arrow") }).overCurrentContext(isPresented: $isShowingAlert, content: { return AnyView ( PopoutAlertView( title: "Reset board", content: "Really want to reset board?", onTapButtonCancel: { isShowingAlert = false }, onTapButtonOk: { currentBrain.reset() isShowingAlert = false }) ) }) }
  18. protocol View { associatedtype Body : View @ViewBuilder var body:

    Self.Body { get } } Opaque Types View ❌ some View ❌
  19. isPresented: Binding<Bool>, afterDismiss: (() -> Void)? = nil, content: ()

    -> AnyView ) -> some View { if isPresented.wrappedValue && currentOverCurrentContextUIHost == nil { let uiHost = UIHostingController(rootView: content()) currentOverCurrentContextUIHost = uiHost uiHost.modalPresentationStyle = .overCurrentContext uiHost.view.backgroundColor = UIColor.clear let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.present(uiHost, animated: false, completion: nil) } else { if let uiHost = currentOverCurrentContextUIHost { uiHost.dismiss(animated: false, completion: {}) currentOverCurrentContextUIHost = nil afterDismiss?() } } return self } }
  20. var resetButton: some View { Button(action: { isShowingAlert = true

    }, label: { sideViewButton(imageName: "arrow") }).overCurrentContext(isPresented: $isShowingAlert, content: { return AnyView ( PopoutAlertView( title: "Reset board", content: "Really want to reset board?", onTapButtonCancel: { isShowingAlert = false }, onTapButtonOk: { currentBrain.reset() isShowingAlert = false }) ) }) }
  21. None
  22. None
  23. protocol DBLoader: ObservableObject { var title: String { get set

    } var artist: String { get set } var searchResult: Data { get set } func search() } class iTunesDBLoader: DBLoader { var title: String var artist: String @Published var searchResult: Data? func search() {......} } class MBDBLoader: DBLoader { var title: String var artist: String @Published var searchResult: Data? func search() -> Data {......} } DBLoader iTunesDBLoader MBDBLoader DBLoader
  24. DetailView() .environmentObject(iTunesDBLoader(title: title, artist: artist)) struct DetailView: View { @EnvironmentObject

    var dbLoader: DBLoader var body: some View { ...... } }
  25. class DBLoader: ObservableObject{ var title: String? var artist: String? @Published

    var searchResult: Data? func search(){ } } class iTunesDBLoader: DBLoader { override func search() { } } class MBDBLoader: DBLoader { override func search() { } } DBLoader iTunesDBLoader MBDBLoader DBLoader
  26. DetailView() .environmentObject(iTunesDBLoader(title: title, artist: artist)) struct DetailView: View { @EnvironmentObject

    var dbLoader: DBLoader var body: some View { ...... } }
  27. @frozen @propertyWrapper struct EnvironmentObject<ObjectType> where ObjectType : ObservableObject struct DetailView:

    View { @EnvironmentObject var dbLoader: DBLoader var body: some View { ...... } }
  28. DBLoaderToPass class DBLoaderToPass: ObservableObject { @Published var loader: DBLoader! init(loader:

    DBLoader) { self.loader = loader } } class DBLoader: ObservableObject{ var title: String? var artist: String? @Published var searchResult: Data? func search(){ } } class iTunesDBLoader: DBLoader { override func search() { } } class MBDBLoader: DBLoader { override func search() { } } DBLoader iTunesDBLoader MBDBLoader DBLoader Any DBLoader
  29. DetailView() .environmentObject( DBLoaderToPass(loader: iTunesDBLoader(title: title, artist: artist) ) ) struct

    DetailView: View { @EnvironmentObject var dbLoader: DBLoader var body: some View { ...... } }
  30. DBLoaderToPass class DBLoaderToPass: ObservableObject { @Published var loader: DBLoader! init(loader:

    DBLoader) { self.loader = loader } } class DBLoader: ObservableObject{ var title: String? var artist: String? @Published var searchResult: Data? func search(){ } } class iTunesDBLoader: DBLoader { override func search() { } } class MBDBLoader: DBLoader { override func search() { } } DBLoader iTunesDBLoader MBDBLoader DBLoader Any DBLoader
  31. import Combine class DBLoaderToPass: ObservableObject { @Published var loader: DBLoader!

    var anyCancellable: AnyCancellable? = nil init(loader: DBLoader) { self.loader = loader anyCancellable = loader.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() } } }
  32. import Combine class DBLoaderToPass: ObservableObject { @Published var loader: DBLoader!

    var anyCancellable: AnyCancellable? = nil init(loader: DBLoader) { self.loader = loader anyCancellable = loader.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() } } }
  33. import Combine class DBLoaderToPass: ObservableObject { @Published var loader: DBLoader!

    var anyCancellable: AnyCancellable? = nil init(loader: DBLoader) { self.loader = loader anyCancellable = loader.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() } } }
  34. None
  35. Twitter: @Megabits_mzq