问题
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