Ios 从泛型返回类型获取实际类型
我在Ios 从泛型返回类型获取实际类型,ios,swift,generics,uiview,xib,Ios,Swift,Generics,Uiview,Xib,我在UIView上有一个扩展,它加载特定类型和名称的nib: 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 {
UIView
上有一个扩展,它加载特定类型和名称的nib:
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
}
}
这不起作用,因为t.self
的结果始终是UIView,即使调用fromNib
方法的提示是class。如果我尝试硬编码这样的类:
if let view = Hint.fromNib(){
self.addSubview(view)
view.frame = self.bounds
}
Bundle(for: Hint.self).loadNibNamed(String(describing: Hint.self), owner: nil, options: nil)
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
然后一切都开始了。如何获取类的类型名,在该类上实际调用了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文件只有一个标签和一个图像视图,但我想这与当前问题几乎无关。我使用完全相同的方法遇到了完全相同的问题,甚至将其命名为相同的问题。我无法使用当前的类类型,因为编译器假定它是
UIView
,而不是它的子类
所发生的是Hint.fromNib()
最终与UIView.fromNib()
完全相同,因为T
不依赖于调用它的类,所以T
被推断为UIView
。您需要做的是通过指定您希望获得的视图类型来帮助编译器推断正确的类型
让提示:提示?=UIView.fromNib()
我想补充一点,当您正确使用guard
时,first
比[0]
更安全,因此我将更改您的方法,使其如下所示:
if let view = Hint.fromNib(){
self.addSubview(view)
view.frame = self.bounds
}
Bundle(for: Hint.self).loadNibNamed(String(describing: Hint.self), owner: nil, options: nil)
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
您想知道调用的类
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
}
}
作品和印刷品:
<TESTS.MyXib: 0x7f9531408aa0; frame = (0 0; 30 30); autoresize = W+H; layer = <CALayer: 0x60000002b8e0>>
是等价的
因此,即使这个答案解决了这个问题,它也没有回答这个问题。试试
let-hint:hint=UIView.fromNib()
。我遇到了相同的问题。在调用方法之前,您是否尝试定义类型?i、 e.if-let-view:Hint=Hint.fromNib()
Oops。。埃米利奥以10比1击败了我seconds@EmilioPelaez我刚刚试过,所以现在它没有崩溃,但是从nib加载的视图不可见(使用我提供的代码)。。。“必须设置一些断点…”Whirlwind我详细说明了答案。我认为使用Hint?
可能更好,但我的方法没有使用optionals,所以我没有尝试过。好的,我也会尝试你的代码。另外,这一行,let bundle=bundle(for:T.self)
不会编译。需要对任何类进行显式转换。。。编译器建议这样做:let bundle=bundle(for:T.self as!AnyClass)
。我只得到想要的结果,1)将nib的内容加载到我的自定义视图中,并在设计时呈现(在情节提要中可见),2)当然在运行时加载,如果我硬编码Hint.self
而不是T.self
,我已经添加了我的Hint类的实现。。。我希望它能对解决这个问题有所帮助。谢谢!好问题!用更多(可能是肤浅的)想法更新了答案。