How to instantiate a class and init from a string in Swift?

I can create an instance of a class from a string in ObjC. For example, I defined a new DBCell class using a subclass of UITableViewCell, and I create a class from the 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 to translate the codes in Swift, I redefined the 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 a class and call the corresponding init function?

+6
source share
1 answer

Swift is more statically typed, which makes it much safer at runtime. For example, if any of the lines is incorrect, you will crash (or, in the best case, do nothing calmly, which could be worse than a failure), and the compiler cannot catch it.

OK, but how do you deal with this template? The best way, IMO, in Swift is to explicitly 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 DBCell , but skip the line in the storyboard, everything will work as expected, not a crash or silent failure, as in ObjC.

Swift is really smart in these comparisons. The cellMapping type cellMapping above [String: DBCell.Type] , so if you have a special init for DBCell , it will be available. But if your dictionary looks like this:

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

then type [String: UITableViewCell.Type] . Swift automatically determines the most specific class that spans all values. If you added a type to this list that did not use any method that you really use, Swift can catch it at compile time. And if you make a mistake and add something that is not even a table cell:

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

then Swift will give you a compilation time message that you created AnyObject . It's really nice to write safe, but flexible code, all for the cost of the dictionary.

+15
source

Source: https://habr.com/ru/post/975345/


All Articles