我可以在ObjC中从string中实例化类。例如,我通过子类化UITableViewCell定义了新的DBCell类,并使用这些代码从name实例化了类:
DBCell *cell=[tableView dequeueReusableCellWithIdentifier:cellClassname];
if (cell==nil) {
Class cellClass=NSClassFromString(cellClassname);
cell=[cellClass alloc];
cell=[cell initWithStyle:cellStyle reuseIdentifier:cellClassname];
}
现在我需要将代码迁移到Swift,我在Swift中重新定义了DBCell类:
class DBCell: UITableViewCell {
var label:String?
var key:String?
var managedObject:NSManagedObject?
var delegate:AnyObject?
convenience override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
self.init(style: style, reuseIdentifier: reuseIdentifier)
self.textLabel.font=UIFont.preferredFontForTextStyle(UIFontTextStyleCaption1)
self.backgroundColor=UIColor.blackColor()
self.textLabel.backgroundColor=UIColor.blackColor()
}
}
但是如何实例化类并调用相应的init函数?
答案 0 :(得分:17)
Swift更加静态类型化,这使得它在运行时更加安全。例如,如果任何字符串都是错误的,那么你会崩溃(或者最好悄悄地做什么,这可能比崩溃更糟糕)并且编译器无法为你捕获它。
好的,但是你如何处理这种模式?在Swift中,IMO的最佳方式是显式并创建映射。
let cellMapping = [
"DBCell": DBCell.self,
]
if let cellClass = cellMapping[cellClassName] {
let cell = cellClass(style: cellStyle, reuseIdentifier: cellClassName)
// use cell
}
现在,当您重构并更改DBCell
的名称,但错过了Storyboard中的字符串时,一切都将按预期继续工作,而不是像在ObjC中那样崩溃或悄然失败。
Swift对这些映射也非常聪明。上面的cellMapping
类型为[String: DBCell.Type]
,因此,如果init
有特殊DBCell
,则可以使用let cellMapping = [
"DBCell": DBCell.self,
"OtherCell": UITableViewCell.self
]
。但如果你的字典看起来像:
[String: UITableViewCell.Type]
然后类型为let cellMapping = [
"DBCell": DBCell.self,
"OtherCell": UITableViewCell.self,
"BadCell": UICollectionViewCell.self
]
。 Swift自动计算出涵盖所有值的最具体的类。如果你在这个列表中添加了一个没有实际使用的方法的类型,Swift可以在编译时捕获它。如果你犯了一个错误并添加了一些甚至不是表视图单元格的东西:
AnyObject
然后Swift会给你一个编译时警告,你已经创建了{{1}}。这非常适合编写安全但灵活的代码,所有代码都是以字典为代价的。