简体   繁体   English

Swift 协议属性与代表

[英]Swift protocol properties with delegates

I am trying to setup a success/error view on a controller via protocol and extensions.我正在尝试通过协议和扩展在 controller 上设置成功/错误视图。

What I want to achieve is that I want to get into the state where it is enough to implement the protocol on a controller, and from there get access to the successView (no additional boilerplate).我想要实现的是,我想进入 state,它足以在 controller 上实现协议,并从那里访问 successView(没有额外的样板)。

This is what I have so far:这是我到目前为止所拥有的:

protocol SucessViewProtocol where Self: UIViewController {
    
    func initSuccessView()

    var successView: UIView! { get set }
    var topConstraint: NSLayoutConstraint! { set get }

    func showSuccess()
    func hideSucess()
}

extension SucessViewProtocol {

    func showSuccess() {
        //animate displaying success message
    }

    func hideSucess() {
        //animate hiding success message
    }

    func initSuccessView()  {
        successView = UIView()
        topConstraint = NSLayoutConstraint()
        // init success view and top constraint
    }
}

Now when I implement the protocol on the controller it looks like this:现在,当我在 controller 上实现协议时,它看起来像这样:

// MARK: SuccessView
extension ConsumingViewController: SucessViewProtocol {
    var successView: UIView! {
        get {
            //getter
        }
        set {
            //setter
        }
    }

    var topConstraint: NSLayoutConstraint! {
        get {
            //getter
        }
        set {
            //setter
        }
    }
 
}

I guess my problem is obvious because I get the successView and topConstraint as properties inside my controller that is implementing the SucessViewProtocol.我想我的问题很明显,因为我在实现 SucessViewProtocol 的 controller 中获得了 successView 和 topConstraint 作为属性。 I am initializing the properties from the protocol inside the extension, so what I need would be just an access to these properties (not declaring them again in my controller).我正在从扩展中的协议初始化属性,所以我需要的只是访问这些属性(而不是在我的控制器中再次声明它们)。 I guess I am missing some "glue" part between the protocol - extension - controller我想我在协议 - 扩展 - controller 之间遗漏了一些“胶水”部分

I want to be able to implement the protocol on a controller, call initSuccessView() and from there it should just be enough to call showSuccess and hideSuccess .我希望能够在 controller 上实现该协议,调用initSuccessView()并从那里调用showSuccesshideSuccess就足够了。

Edit:编辑:

This is how I want to use this construct:这就是我想使用这个结构的方式:

class ConsumingViewController: UIViewController {
   func viewDidLoad() {
     initSuccessView()
     
     loadData()
   }

   private func loadData() {
     //successfullyloaded
     showSuccess()
   }

}

// MARK: SuccessView
extension ConsumingViewController: SucessViewProtocol {
  var successView: UIView! {
    get {
        //getter
    }
    set {
        //setter
    }
  } *PROBLEMATIC*

  var topConstraint: NSLayoutConstraint! {
    get {
        //getter
    }
    set {
        //setter
    }
  } *PROBLEMATIC*

} }

As I said, the problem is that the properties successView and topConstraing are being redeclared inside ConsumingViewController (because they are part of the protocol).正如我所说,问题在于属性 successView 和 topConstraing 在 ConsumingViewController 中被重新声明(因为它们是协议的一部分)。 I would need to actually not be visibile inside the controller, but just being used inside the extension.我需要在 controller 中实际上不可见,而只是在扩展中使用。 But then there is the problem with stored properties inside extensions...但是扩展中的存储属性存在问题......

May be you want this?可能是你想要的吗?

protocol SucessViewProtocol {
    func showSuccess()
    func hideSucess()
}

fileprivate struct Key {
    static var runtimeKey: Int = 0
}

extension SucessViewProtocol where Self: UIViewController  {
    var successView: UIView? {
        get {
            return objc_getAssociatedObject(self, &Key.runtimeKey) as? UIView
        }
        set {
            objc_setAssociatedObject(self, &Key.runtimeKey, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }

    func showSuccess() {
        successView = UIView()
        //animate displaying success message
        view.addSubview(successView)
    }

    func hideSucess() {
        //animate hiding success message
        successView?.removeFromSuperview()
    }
}

add protocol variables inside main scope not extension scope UIViewController like this.像这样在主 scope 中添加协议变量而不是扩展 scope UIViewController。

public class ViewController: UIViewController, SucessViewProtocol {
    var successView: UIView!
    var topConstraint: NSLayoutConstraint!    
}

By doing this you do not need to define getter and setter for properties通过这样做,您不需要为属性定义 getter 和 setter

and inside ViewDidLoaded you can initSuccessView:在 ViewDidLoaded 中,您可以初始化SuccessView:

public override func viewDidLoad() {
        super.viewDidLoad()
        
        self.initSuccessView()
    }

and call custom function:并调用自定义 function:

func show() {
        self.showSuccess()
    }
    
    func hide() {
        self.hideSucess()
    }

Solution = Optional Porotocols解决方案 = 可选协议

You just need add properties to the extension as well to make them optional .您只需要向扩展添加属性,并使它们成为可选的。

protocol SucessViewProtocol where Self: UIViewController {

    func initSuccessView()

    var successView: UIView! { get set }
    var topConstraint: NSLayoutConstraint! { set get }

    func showSuccess()
    func hideSucess()
}

extension SucessViewProtocol {

    // 👇🏼------ these 2 properties added ------👇🏼
    var successView: UIView! { get{ nil } set{} }
    var topConstraint: NSLayoutConstraint! { get{ nil } set{} }

    func showSuccess() {}

    func hideSucess() {}

    func initSuccessView()  {
        successView = UIView()
        topConstraint = NSLayoutConstraint()
    }
}

Then, when you conform SucessViewProtocol on ConsumingViewController you won't require to implement protperties.然后,当您在ConsumingViewController上遵循SucessViewProtocol时,您将不需要实现属性。

// MARK: SuccessView
extension ConsumingViewController: SucessViewProtocol {
    // There's NO compiler error here!
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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