简体   繁体   中英

How to make a SwiftUI View a property of a Protocol

I'm trying to extend a protocol so that a certain few impls of the protocol have a view associated with them. However, because a SwiftUI View is a protocol, this is proving to be a challenge.

import SwiftUI


protocol ParentProtocol {
  var anyProperty: String { get }
}

protocol ChildProtocol : ParentProtocol {
  associatedtype V
  var someView: V { get }
}

class ChildImpl : ChildProtocol {
  var someView : some View {
    Text("Hello World")
  }

  var anyProperty: String = ""

}

class ChildMgr {
  var child: ParentProtocol = ChildImpl()

  func getView() -> some View {
    guard let child = child as? ChildProtocol else { return EmptyView() }
    return child.someView
  }
}

Its not clear to me where to constrain the ChildProtocol's associated type to a View (or Text for that matter).

At the guard let child =... I get the following compiler error: Protocol 'ChildProtocol' can only be used as a generic constraint because it has Self or associated type requirements

and when returning the chid's view I get: Member 'someView' cannot be used on value of protocol type 'ChildProtocol'; use a generic constraint instead Member 'someView' cannot be used on value of protocol type 'ChildProtocol'; use a generic constraint instead

I think the answer may be in this thread: https://developer.apple.com/forums/thread/7350 but frankly its confusing on how to apply it to this situation.

Don't use runtime checks. Use constrained extensions.

I also don't see a reason for you to be using classes.

protocol ChildProtocol: ParentProtocol {
  associatedtype View: SwiftUI.View
  var someView: View { get }
}

final class ChildImpl: ChildProtocol {
  var someView: some View {
    Text("Hello World")
  }

  var anyProperty: String = ""
}

final class ChildMgr<Child: ParentProtocol> {
  var child: Child

  init(child: Child) {
    self.child = child
  }
}

extension ChildMgr where Child: ChildProtocol {
  func getView() -> some View {
    child.someView
  }
}

extension ChildMgr {
  func getView() -> some View {
    EmptyView()
  }
}

extension ChildMgr where Child == ChildImpl {
  convenience init() {
    self.init(child: .init())
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM