首页 > 解决方案 > 通用:有没有办法让编译器检查 T 是一个特定的 UIView 子类?

问题描述

目前,我有以下方便的通用函数,它使我能够从 XIB 创建自定义视图

extension UIView {
    static func instanceFromNib<T: UIView>() -> T {
        return UINib(nibName: String(describing: self), bundle: nil).instantiate(withOwner: self, options: nil)[0] as! T
    }
}

用法是

let colorPickerView: ColorPickerView
// Returned type from ColorPickerView.instanceFromNib is UIView, not ColorPickerView.
colorPickerView = ColorPickerView.instanceFromNib()

但是,编译器只能知道 is 的返回ColorPickerView.instanceFromNibUIView。它不知道ColorPickerView.instanceFromNibis in fact的返回值ColorPickerView

以下代码将毫无问题地编译,但会导致运行时错误。

let colorPickerView: UIButton  // UIButton is child of UIView.
// Returned type from ColorPickerView.instanceFromNib is UIView, not ColorPickerView.
colorPickerView = ColorPickerView.instanceFromNib()

我想知道,有没有办法进一步改进上述泛型函数,以便我们可以

// No issue. Returned type from CustomView1.instanceFromNib is CustomView1. 
let customView1: CustomView1 = CustomView1.instanceFromNib()

// No issue. Returned type from CustomView2.instanceFromNib is CustomView2. 
let customView2: CustomView2 = CustomView2.instanceFromNib()

// Compile error. Compiler knows the returned type is CustomView1.
let customView3: CustomView3 = CustomView1.instanceFromNib()

标签: iosswiftgenericsuikit

解决方案


您可以对此进行改进,以使上述代码失败,但永远无法确定它具有正确的类型。

要处理上述代码,您只需更改instanceFromNib()为返回 Self,而不是“调用者请求的任何类型”。

static func instanceFromNib() -> Self {
    UINib(nibName: String(describing: self), bundle: nil)
        .instantiate(withOwner: self, options: nil)[0] as! Self
}

但是该 NIB 仍然有可能保存错误的类型,并且直到运行时才会发现,因为您必须从文件中加载数据才能知道。


推荐阅读