How to instantiate class and init from string in Swift?

房东的猫 提交于 2019-12-08 22:51:07

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/25864108/how-to-instantiate-class-and-init-from-string-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!