自类型作为闭包中的参数

时间:2019-04-06 13:26:26

标签: swift generics

UIView的实例是否可以调用执行闭包的方法,并且该闭包内部引用同一实例?这是非通用版本:

import UIKit

public extension UIView {
    func layout(from: (UIView) -> ()) {
        from(self)
    }
}

例如,当我使用UILabel调用它时,我无权访问文字要求。我可以在闭包内部引用UILabel吗?我希望这样的事情会起作用:

func layout(from: (Self) -> ()) {
    from(self)
}

但是它不能编译。有解决方法吗?这就是我想要的:

let label = UILabel(frame: .zero)

label.layout { $0.textAlignment = .natural } // Currenly not working, since $0 = UIView.

2 个答案:

答案 0 :(得分:2)

不同的方法:具有相关类型的协议扩展。

protocol Layout {
    associatedtype View : UIView = Self
    func layout(from: (View) -> ())
}

extension Layout where Self : UIView {
    func layout(from: (Self) -> ()) {
        from(self)
    }
}

extension UIView : Layout {}

let label = UILabel(frame: .zero)
label.layout { $0.textAlignment = .natural }

答案 1 :(得分:1)

有不同的方法。

首先,您可以使用closures' variable capturing system来直接在闭包内部使用变量,而无需将其作为参数传递。

public extension UIView {
    func layout(from: () -> ()) {
        from()
    }
}

label.layout { label.textAlignment = .natural }

否则,如果您要传递通用的UIView并相应地将行为更改为特定的行为-因为看起来您肯定知道要使用的类型,则可以使用向下转换:

public extension UIView {
    func layout(from: (UIView) -> ()) {
        from(self)
    }
}

let label = UILabel(frame: .zero)

label.layout { ($0 as! UILabel).textAlignment = .natural }

无论如何,你为什么这样做:

label.layout { $0.textAlignment = .natural }

代替:

label.textAlignment = .natural

是否有特定原因不这样做?我想幕后还有更大的事情,我只是很好奇。