我有一个UIButton的自定义子类:
import UIKit
@IBDesignable
class MyButton: UIButton {
var array : [String]?
}
它是IBDesignable,我已将其设置为故事板中其中一个按钮的自定义类。我想使它通用,以便数组不必是String对象之一。所以,我试过这个:
import UIKit
@IBDesignable
class MyButton<T>: UIButton {
var array : [T]?
}
但是,我不确定如何将其设置为IB中的班级。我尝试了MyButton<String>
或MyButton<Int>
,但Interface Builder只删除尖括号部分并获得以下编译错误:
Command /Applications/Xcode6-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 254
有没有办法使用通用自定义类,还是不支持?
答案 0 :(得分:35)
Interface Builder通过ObjC运行时与您的代码“对话”。因此,IB只能访问代码中可在ObjC运行时中表示的功能。 ObjC不做泛型,因此IB没有办法告诉运行时要使用的泛型类的特化。 (并且没有专门化就无法实例化Swift泛型类,因此在尝试实例化MyButton
而不是MyButton<WhateverConcreteType>
时会出错。)
(当你破坏其他东西时,你可以认识到在IB中工作的ObjC运行时:在nib / storyboard中尝试使用带有出口/动作的纯Swift类会产生关于ObjC内省的运行时错误。保留连接出口的相应代码声明已经改变或消失,给出了关于KVC的运行时错误。等等。)
忽略运行时问题并以稍微不同的方式表达......让我们回到IB需要知道的内容。请记住,nib加载系统是在运行时实例化故事板中的任何内容。因此,即使类中包含泛型类型参数的部分不是@IBInspectable
,nib仍然需要知道要加载的泛型类的特化。因此,对于允许您使用泛型类进行视图的IB,IB必须有一个位置来确定nib应该使用的类的哪个特化。它没有 - 但这会成为一个伟大的feature request。
与此同时,如果您的MyButton
类仍然有助于涉及一些通用存储,那么您可以考虑让MyButton
引用另一个包含通用存储的类。 (它必须以这样的方式这样做,即在编译时不知道所述存储的类型 - 否则该其他类的类型参数必须传播回MyButton
。)< / p>
答案 1 :(得分:1)
我遇到了同样的问题,我想使用以下结构:
import UIKit
protocol MyDataObjectProtocol{
var name:String { get}
}
class MyObjectTypeOne:MyDataObjectProtocol{
var name:String { get { return "object1"}}
}
class MyObjectTypeTwo:MyDataObjectProtocol{
var name:String { get { return "object2"}}
}
class SpecializedTableViewControllerOne: GenericTableViewController<MyObjectTypeOne> {
}
class SpecializedTableViewControllerTwo: GenericTableViewController<MyObjectTypeTwo> {
}
class GenericTableViewController<T where T:MyDataObjectProtocol>: UITableViewController {
// some common code I don't want to be duplicated in
// SpecializedTableViewControllerOne and SpecializedTableViewControllerTwo
// and that uses object of type MyDataObjectProtocol.
}
但正如前面的回答所解释的那样,这是不可能的。所以我设法使用以下代码来处理它:
import UIKit
protocol MyDataObjectProtocol{
var name:String { get}
}
class MyObjectTypeOne:MyDataObjectProtocol{
var name:String { get { return "object1"}}
}
class MyObjectTypeTwo:MyDataObjectProtocol{
var name:String { get { return "object2"}}
}
class SpecializedTableViewControllerOne: GenericTableViewController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
super.object = MyObjectTypeOne()
}
}
class SpecializedTableViewControllerTwo: GenericTableViewController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
super.object = MyObjectTypeTwo()
}
}
class GenericTableViewController : UITableViewController {
var object : MyDataObjectProtocol?
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
label.text = object?.name
}
// some common code I don't want to be duplicated in
// SpecializedTableViewControllerOne and SpecializedTableViewControllerTwo
// and that uses object of type MyDataObjectProtocol.
}
现在我的标签出口显示&#34; object1&#34;当我将SpecializedTableViewControllerOne
作为我的视图控制器的自定义类链接在故事板中时,&#34; object2&#34;如果我链接到SpecializedTableViewControllerTwo
答案 2 :(得分:0)
可以在UIView
中使用通用Interface Builder
。假设您有:
class A<T>: UIView {}
首先,您必须继承通用视图以使其非通用:
class B: A<String> {}
继续使用Interface Builder
中的B类。
之后,您可以在代码中建立@IBOutlet
连接:
@IBOutlet var b: B
它将产生错误,因此要消除此错误,请改用UIView
类,并像这样向下转换:
@IBOutlet var b: UIView
var _b: B {
b as! B
}
完成,现在您的_b
变量的类型为B
,并且可以正常工作。