$30 off During Our Annual Pro Sale. View Details »

先週解決した SwiftUI 問題

先週解決した SwiftUI 問題

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

Megabits_mzq

January 29, 2021
Tweet

More Decks by Megabits_mzq

Other Decks in Programming

Transcript

  1. 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 }) } // ...... } } }
  2. 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 }) }) }
  3. 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)
  4. 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 }) ) }) }
  5. 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 } }
  6. 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 {
  7. 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 {
  8. 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
  9. 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 }) ) }) }
  10. protocol View { associatedtype Body : View @ViewBuilder var body:

    Self.Body { get } } Opaque Types View ❌ some View ❌
  11. 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 } }
  12. 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 }) ) }) }
  13. 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
  14. 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
  15. @frozen @propertyWrapper struct EnvironmentObject<ObjectType> where ObjectType : ObservableObject struct DetailView:

    View { @EnvironmentObject var dbLoader: DBLoader var body: some View { ...... } }
  16. 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
  17. DetailView() .environmentObject( DBLoaderToPass(loader: iTunesDBLoader(title: title, artist: artist) ) ) struct

    DetailView: View { @EnvironmentObject var dbLoader: DBLoader var body: some View { ...... } }
  18. 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
  19. 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() } } }
  20. 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() } } }
  21. 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() } } }