子类和超类的Swift约束协议

子类和超类的Swift约束协议,swift,protocols,swift-protocols,Swift,Protocols,Swift Protocols,我想为UIViewCntroller和UIView实现我自己的HUD,所以我做了以下工作: protocol ViewHudProtocol { func showLoadingView() func hideLoadingView() } extension ViewHudProtocol where Self: UIView { func showLoadingView() { //Show HUD by adding a custom UIView to sel

我想为UIViewCntroller和UIView实现我自己的HUD,所以我做了以下工作:

protocol ViewHudProtocol {
    func showLoadingView()
    func hideLoadingView()
}

extension ViewHudProtocol where Self: UIView {

    func showLoadingView() { //Show HUD by adding a custom UIView to self.}
    }

    func hideLoadingView() {
    }
}
extension ViewHudProtocol where Self: UIViewController {

    func showLoadingView() {
        self.view.showLoadingView() //Error: UIView has no member showLoadingView
    }

    func hideLoadingView() {
        self.view.hideLoadingView() //Error: UIView has no member hideLoadingView
    }
}
extension UIView: ViewHudProtocol {}
现在,我可以轻松地在任何UIView上采用ViewHUD协议来调用
showLoadingView
hideLoadingView
。问题是我想对UIViewController使用相同的协议,所以我这样做了:

protocol ViewHudProtocol {
    func showLoadingView()
    func hideLoadingView()
}

extension ViewHudProtocol where Self: UIView {

    func showLoadingView() { //Show HUD by adding a custom UIView to self.}
    }

    func hideLoadingView() {
    }
}
extension ViewHudProtocol where Self: UIViewController {

    func showLoadingView() {
        self.view.showLoadingView() //Error: UIView has no member showLoadingView
    }

    func hideLoadingView() {
        self.view.hideLoadingView() //Error: UIView has no member hideLoadingView
    }
}
extension UIView: ViewHudProtocol {}
我同意UIView尚未采用该协议的错误。所以我这样做了:

protocol ViewHudProtocol {
    func showLoadingView()
    func hideLoadingView()
}

extension ViewHudProtocol where Self: UIView {

    func showLoadingView() { //Show HUD by adding a custom UIView to self.}
    }

    func hideLoadingView() {
    }
}
extension ViewHudProtocol where Self: UIViewController {

    func showLoadingView() {
        self.view.showLoadingView() //Error: UIView has no member showLoadingView
    }

    func hideLoadingView() {
        self.view.hideLoadingView() //Error: UIView has no member hideLoadingView
    }
}
extension UIView: ViewHudProtocol {}

它是有效的。有更好的方法吗?我的意思是,用
ViewHudProtocol
扩展每个视图感觉都不对,因为不是所有视图都会使用它。如果我可以这样做,“如果UIView控制器需要,则仅隐式地采用UIView的ViewHudProtocol。否则,您可以在需要时在任何UIView上手动采用ViewHudProtocol。”

我会采取这种方法:

  • 创建UIView类
  • 设置视图
  • 声明一个共享对象
  • 显示视图的函数
  • 删除视图的函数。然后在视图控制器中将其称为
    IndicatorView.shared.show()
    IndicatorView.shared.hide()


  • 对于此特定场景,装饰师会工作得更好,并产生更好的设计:

    final class HUDDecorator {
        private let view: UIView
    
        init(_ view: UIView) {
            self.view = view
        }
    
        func showLoadingView() {
            // add the spinner
        }
    
        func hideLoadingView() {
            // remove the spinner
        }
    }
    
    使用Decorator就像为它声明属性一样简单:

    class MyViewController: UIViewController {
        lazy var hudDecorator = HUDDecorator(view)
    }
    
    这将允许任何控制器通过简单地公开此属性来决定是否需要支持显示/隐藏加载视图

    协议对于增强UI组件的外观这样的简单任务来说太具有侵入性,它们的缺点是强制某个类的所有视图公开协议功能,而Decorator方法允许您决定接收该功能的视图实例。

    因此,仅当
    UIViewController.view
    属性符合
    ViewHudProtocol
    时,才需要约束
    UIViewController
    与协议的一致性

    恐怕这是不可能的

    理解问题 让我们更好地看看你的问题

    您有两种类型(UIView和UIViewController),并且希望添加到这两种功能中

    func showLoadingView()
    func hideLoadingView()
    
    米克·韦斯特教给我们的 这种情况在某种程度上类似于米克·韦斯特在托尼·霍克斯系列剧《米克·韦斯特》的开发过程中所面临的情况,文章中描述了一种优雅的解决方案

    解决方案 我们可以将这种方法应用于您的问题,下面是解决方案

    struct HudViewComponent {
    
        let view: UIView
        private let hud: UIView
    
        init(view: UIView) {
            self.view = view
            self.hud = UIView(frame: view.frame)
            self.hud.isHidden = true
            self.view.addSubview(hud)
        }
    
        func showLoadingView() {
            self.hud.isHidden = false
        }
    
        func hideLoadingView() {
            self.hud.isHidden = true
        }
    
    }
    
    protocol HasHudViewComponent {
        var hidViewComponent: HudViewComponent { get }
    }
    
    extension HasHudViewComponent {
        func showLoadingView() {
            hidViewComponent.showLoadingView()
        }
        func hideLoadingView() {
            hidViewComponent.hideLoadingView()
        }
    }
    
    
    就这样,现在您可以将hud功能添加到符合
    HasHudViewComponent
    的任何类型

    class SomeView: UIView, HasHudViewComponent {
        lazy var hidViewComponent: HudViewComponent = { return HudViewComponent(view: self) }()
    }
    

    考虑 正如你所看到的,这个想法是从组件的角度来思考的。 使用hud功能构建组件(
    HudViewComponent
    )。组件只要求最低要求:它需要一个UIView

    接下来定义
    HasHudViewComponent
    ,该属性声明当前类型具有
    HudViewComponent
    属性

    最后,您可以将hud功能添加到任何具有视图(UIView、UIViewController等)的类型中,只需将您的类型与
    HasHudViewComponent
    相一致即可

    class SomeView: UIView, HasHudViewComponent {
        lazy var hidViewComponent: HudViewComponent = { return HudViewComponent(view: self) }()
    }
    
    笔记
    你问了一个有趣的问题,我知道这并不能百分之百地回答你想要的问题,但从实用的角度来看,它应该为你提供一个工具来实现你的需要。

    我将使用以下方法解决这个问题,使用只为所需的视图和/或控制器定义的
    associatedtype
    (在Xcode 11.2/swift 5.1中测试):


    恭喜,这是一个非常聪明的解决方案。