2014-09-16 6 views
6

I Klasse von String in ObjC.For Beispiel instanziiert könnte, ich habe durch Subklassen UITableViewCell neue DBCell Klasse definiert, und ich instanziiert Klasse von Namen mit diesen Codes:Wie instanziieren Sie Klasse und Init aus String in Swift?

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

Jetzt brauche ich Codes zu Swift migrieren, I DBCell Klasse in Swift neu definiert:

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

Aber wie kann ich Klasse instanziiert und rufen die entsprechende init-Funktion?

+0

Ich fühle, dass Ihr Problem durch schlechte Architektur, vor allem das Fehlen von richtig verwendeten Polymorphismus verursacht wird. Könnten Sie bitte mehr von Ihrem ursprünglichen obj-c-Code zeigen? Was ist der Unterschied zwischen verschiedenen Zellen? – Sulthan

+0

@Sulthan Dies ist ein ziemlich häufiges Cocoa-Muster. Was meinst du mit "richtig verwendetem Polymorphismus" in diesem Fall? Der Punkt ist, dass die Zellennamen im Storyboard gespeichert werden, was sehr praktisch und nützlich ist. Die Frage ist, wie dies zu tun ist, während die Sicherheit von Swift beibehalten wird (und es ist eine vernünftige Frage). –

Antwort

15

Swift ist statischer getippt, was es zur Laufzeit viel sicherer macht. Zum Beispiel, wenn einer der Strings falsch ist, werden Sie abstürzen (oder bestenfalls nichts tun, was schlimmer als Absturz sein kann) und der Compiler kann es nicht für Sie fangen.

OK, aber wie gehen Sie mit diesem Muster um? Der beste Weg, IMO, in Swift ist explizit zu sein und ein Mapping zu erstellen.

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

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

Nun, wenn Sie den Namen des DBCell Refactoring und ändern, aber verpassen Sie die Zeichenfolge in das Storyboard, alles wird einfach weiter wie erwartet funktioniert, anstatt Absturz oder leise wie andernfalls wäre es in ObjC.

Swift ist auch sehr intelligent über diese Mappings. Der Typ von cellMapping oben ist [String: DBCell.Type], also wenn Sie eine spezielle init für DBCell hätten, wäre es verfügbar. Aber wenn Ihr Wörterbuch sah aus wie:

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

dann ist der Typ [String: UITableViewCell.Type]. Swift ermittelt automatisch die spezifischste Klasse, die alle Werte abdeckt. Wenn Sie in diese Liste einen Typ hinzugefügt haben, der keine Methode aufweist, die Sie tatsächlich verwenden, kann Swift dies zur Kompilierzeit abfangen. Und wenn Sie einen Fehler gemacht und hinzugefügt etwas, das nicht einmal eine Tabellenansicht Zelle ist:

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

dann Swift wird Ihnen eine Kompilierung Warnung, dass Sie ein AnyObject erstellt haben. Das ist wirklich schön, wenn man sicheren, aber flexiblen Code schreibt, alles für die Kosten eines Wörterbuchs.

+0

Danke, es hat funktioniert! – user1190178

+0

Gibt es eine Möglichkeit, ein Zell-Mapping zu erstellen, das dies mit verschiedenen Typen funktioniert? –

+0

Ich verstehe die Frage nicht. Sie sollten eine neue SO-Frage mit Details zu Ihrem spezifischen Problem stellen. –