我有一个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
有没有办法使用通用自定义类,还是不支持?
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
。)
我遇到了同样的问题,我想使用以下结构:
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.
}
现在,当我将SpecializedTableViewControllerOne
链接到故事板中我的视图控制器的自定义类时,我的标签出口显示“object1”,如果我链接到SpecializedTableViewControllerTwo
,则为“object2”