如何在Swift中从字符串实例化类和init? [英] How to instantiate class and init from string in Swift?

查看:173
本文介绍了如何在Swift中从字符串实例化类和init?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以从ObjC中的字符串实例化类。例如,我已经定义了新的DBCell类通过子类化UITableViewCell,我实例化类从名称与这些代码:

  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?
方便重写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函数?

解决方案

Swift更静态类型,这使得它在运行时更安全。例如,如果任何字符串是错误的,你会崩溃(或最好静静地做什么,这可能比崩溃更糟),编译器不能捕捉它。



OK,但是你如何处理这种模式呢?最好的方式,IMO,在Swift是要显式和创建一个映射。

  let cellMapping = [
DBCell:DBCell.self,
]

if let cellClass = cellMapping [cellClassName] {
let cell = cellClass(s​​tyle:cellStyle,reuseIdentifier:cellClassName)
//使用单元格
}

现在,当你重构并更改 DBCell 的名称时,故事板,一切都将按预期继续工作,而不是像ObjC中那样崩溃或静默失败。



Swift对于这些映射真的很聪明。上面的 cellMapping 的类型是 [String:DBCell.Type] ,因此如果你有一个特殊的 init DBCell ,它会可用。但如果您的字典看起来像:

  let cellMapping = [
DBCell:DBCell.self,
OtherCell:UITableViewCell.self
]

那么类型是 [String:UITableViewCell.Type] 。 Swift自动计算出包含所有值的最具体的类。如果你添加一个类型到这个列表,没有一个你实际使用的方法,Swift可以在编译时捕获它。如果你犯了一个错误,并添加了一个甚至不是表格视图单元格:

  let cellMapping = [
DBCell:DBCell.self,
OtherCell:UITableViewCell.self,
BadCell:UICollectionViewCell.self
]
pre>

然后Swift会给你一个编译时间警告,你创建了一个 AnyObject 。这是非常好的写作安全,但灵活的代码,所有的代价字典。


I could instantiate class from string in ObjC.For example,I have defined new DBCell class through subclassing UITableViewCell,and I instantiate class from name with these codes:

 DBCell *cell=[tableView dequeueReusableCellWithIdentifier:cellClassname];
    if (cell==nil) {
        Class cellClass=NSClassFromString(cellClassname);
        cell=[cellClass alloc];
        cell=[cell initWithStyle:cellStyle reuseIdentifier:cellClassname];
    }

Now I need migrate codes to Swift,I have redefined DBCell class in Swift:

 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()
    }
    }

But how can I instantiate class and invoke the appropriate init function?

解决方案

Swift is more statically typed, which makes it much safer at runtime. For instance, if any of the strings are wrong, you'll crash (or at best quietly do nothing, which can be worse than crashing) and the compiler can't catch it for you.

OK, but how do you deal with this pattern? The best way, IMO, in Swift is to be explicit and create a mapping.

let cellMapping = [
  "DBCell": DBCell.self,
]

if let cellClass = cellMapping[cellClassName] {
  let cell = cellClass(style: cellStyle, reuseIdentifier: cellClassName)
  // use cell
}

Now when you refactor and change the name of DBCell, but miss the string in the Storyboard, everything will just keep working as expected, rather than crashing or quietly failing like it would in ObjC.

Swift is really smart about these mappings, too. The type of cellMapping above is [String: DBCell.Type], so if you had a special init for DBCell, it would be available. But if your dictionary looked like:

let cellMapping = [
  "DBCell": DBCell.self,
  "OtherCell": UITableViewCell.self
]

then the type is [String: UITableViewCell.Type]. Swift automatically figures out the most specific class that covers all the values. If you added a type into this list that didn't have some method you actually use, Swift can catch that at compile time. And if you made a mistake and added something that isn't even a table view cell:

let cellMapping = [
  "DBCell": DBCell.self,
  "OtherCell": UITableViewCell.self,
  "BadCell": UICollectionViewCell.self
]

then Swift will give you a compile time warning that you've created an AnyObject. That's really nice in writing safe but flexible code, all for the cost of a dictionary.

这篇关于如何在Swift中从字符串实例化类和init?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆