从泛型返回类型获取实际类型

时间:2017-01-22 17:59:35

标签: ios swift generics uiview xib

我在UIView上有一个扩展名,用于加载某个类型和名称的笔尖:

extension UIView {

    class func fromNib<T : UIView>() -> T? {

        guard let nib = Bundle(for: T.self).loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0]
            else {
                return nil
        }
        return nib as? T
    }
}

现在在我的Hint类(UIView的子类)中,我使用上面的扩展名:

 if let view = Hint.fromNib(){
        self.addSubview(view)
        view.frame = self.bounds         
 }

这不起作用,因为T.self的结果始终是UIView,即使提示是调用fromNib方法的类。如果我尝试对这样的类进行硬编码:

Bundle(for: Hint.self).loadNibNamed(String(describing: Hint.self), owner: nil, options: nil)
然后一切正常。如何获取实际调用fromNib()方法的类的类型名称?

这是我的提示课:

class Hint:UIView {

     required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        if let view = UIView.fromNib(){
            self.addSubview(view)
            view.frame = self.bounds

        }

    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        if let view = UIView.fromNib(){
            self.addSubview(view)
            view.frame = self.bounds
        }
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        if let view = UIView.fromNib(){
            self.addSubview(view)
            view.frame = self.bounds
        }
    }

}

所以一切都很简单。一个nib文件只有一个标签和一个图像视图,但我想这与当前问题几乎无关。

2 个答案:

答案 0 :(得分:1)

我用完全相同的方法遇到了完全相同的问题,甚至将其命名为相同。我无法使用当前的类类型,因为编译器假定它是UIView而不是它的子类。

Hint.fromNib()最终与UIView.fromNib()完全相同,因为T并不依赖于被调用的类,所以会发生什么事情,所以T被推断为UIView。您需要做的是通过指定您希望获得的视图类型来帮助编译器推断出正确的类型。

let hint: Hint? = UIView.fromNib()

我想补充一点,当您正确使用guard时,first[0]更安全,所以我会将您的方法更改为:

let bundle = Bundle(for: T.self)
let nib = bundle.loadNibNamed(String(describing: T.self), owner: nil, options: nil)
guard let view = nib?.first as? T else {
  return nil
}
return view

答案 1 :(得分:1)

您想知道调用类fromNib()的类型,即类方法中的self

extension UIView {
    class func fromNib<T : UIView>() -> T? {
        guard
            let nibs = Bundle(for: self).loadNibNamed(String(describing: self), owner: nil, options: nil),
            let nib = nibs.first
            else {
                return nil
        }

        return nib as? T
    }
}

以下内容:

if let viewFromXib = MyXib.fromNib(){            
    view.addSubview(viewFromXib)
    viewFromXib.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 30, height: 30))
    print(viewFromXib)
}

工作和打印:

<TESTS.MyXib: 0x7f9531408aa0; frame = (0 0; 30 30); autoresize = W+H; layer = <CALayer: 0x60000002b8e0>>

我真的不明白如何推断返回类型T

更新

我正在深入研究如何推断返回类型T,答案是:它没有。

此:

class func fromNib() -> UIView? {
    guard
        let nibs = Bundle(for: self).loadNibNamed(String(describing: self), owner: nil, options: nil),
        let nib = nibs.first
        else {
            return nil
    }

    return nib as? UIView
}

等同。

所以,即使这个答案正在解决问题,也没有回答这个问题。