2017-11-30 2 views
1

Ich versuche, einige arbeiten aber hässlich Code zu verfeinern.Swift: Gegossene TabelleCell als variable Klasse

Meine App verfügt über fünf TableViews, von denen jede eine andere Art von Daten anzeigt (mit unterschiedlichen Zellenlayouts). Da die Datentypen ähnlich sind und viele ähnliche Methoden erfordern (zum Herunterladen, Codieren usw.), habe ich eine TableViewController: UITableViewController-Klasse eingerichtet, die als Oberklasse für die fünf TableViewController-Unterklassen dient. Innerhalb dieser Oberklasse habe ich die Standardmethode "cellForRowAt", aber sie ist aufgebläht und repetitiv. Ich möchte es vereinfachen.

Mein Problem (ich denke) ist die multiple "let cell =" Anweisungen, die alle als eine andere Art von TableViewCell abhängig von den Datentypen umgewandelt werden. Zum Beispiel muss mein DataType.SCHEDULES-Datentyp eine SchedulesTableViewCell mit reuseID von "SchedulesCell" erhalten. Ich kann sie nicht alle zur selben TableViewCell-Klasse machen, da sie jeweils eigene IBOutlet-Ansichten haben.

Um die Sache hässlicher zu machen, hat jeder TableView zwei Zellprototypen, und ich muss in der Lage sein, eine ARTICLE-Zelle und eine DETAIL-Zelle für jeden Datentyp zu generieren.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

    // get the article and row type 
    let article = getArticleFor(indexPath: indexPath) 
    let cellType = getCellTypeFor(indexPath: indexPath) 

    // create either an ARTICLE row or a DETAIL row. 
    // (simplified for SO posting. Each "case" is actually 
    // 5-6 lines of nearly identical code) 
    switch cellType { 

    // for the ARTICLE cell prototype 
    case CellType.ARTICLE: 

     // get the right table cell matching the datatype 
     switch self.datatype { 

     case DataType.SCHEDULES: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "SchedulesCell") as! SchedulesTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.LUNCH: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "LunchCell") as! LunchTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.EVENTS: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "EventsCell") as! EventsTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.DAILY_ANN: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "DailyannCell") as! DailyannTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.NEWS: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "NewsCell") as! NewsTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     } 
    // or for the DETAIL cell prototype 
    case CellType.DETAIL: 

     // get the right table cell matching the datatype 
     switch self.datatype { 

     case DataType.SCHEDULES: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "SchedulesDetailsCell") as! ScheduleDetailTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.LUNCH: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "LunchDetailsCell") as! LunchDetailsTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.EVENTS: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "EventsDetailsCell") as! EventsDetailTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.DAILY_ANN: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "DailyannDetailCell") as! DailyannDetailsTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 

     case DataType.NEWS: 
      let cell = tableView.dequeueReusableCell(withIdentifier: "NewsDetailCell") as! NewsDetailTableViewCell 
      cell.fillCellWith(article: article) 
      cell.otherMethod2() 
      cell.otherMethod3() 
      return cell 
     } 
    } 
} 

Ich hatte ursprünglich jeden „Zelle lassen =“ Fall innerhalb der eigenen Unterklassen ‚cellForRowAt‘ Methoden, aber ich wiederhole sehr ähnlichen Code in jeder Unterklasse, die dumm zu sein schien. Auf der anderen Seite hat der obige Code die Wiederholung in eine einzelne Klasse verschoben, aber die Wiederholung nicht entfernt, also ist es immer noch albern, aber an einem anderen Ort.

Ich mag das Gefühl, wenn ich ein Wörterbuch der Klassen machen könnte, so etwas wie dieses ...

let tableCellClasses = [DataType.SCHEDULES : ScheduleTableViewCell, 
        DataType.LUNCH : LunchTableViewCell 
        etc. 

... dann könnte ich meine „lassen Zelle =“ machen Aussagen allgemeineren, wie ...

let cell = tableView.dequeueReusableCell(withIdentifier: identifier[dataType]) as! tableCellClasses[dataType] 

aber kann nicht scheinen, einen Weg zu finden, damit es funktioniert.

Wie gesagt, es funktioniert, aber es ist hässlich. Ich arbeite in einer High School, also möchte ich, dass Studenten, die das Repo ansehen, sauberen, gut strukturierten Code sehen - also schieße ich besser als nur "es funktioniert".

Irgendwelche Vorschläge?

Antwort

1

könnten Sie Swifts Meta-Typen verwenden und was nicht, aber an Ihrem Code suchen, alle Ihre Zelle Subklassen teilen die gleichen Methoden:

cell.fillCellWith(article: article) 
cell.otherMethod2() 
cell.otherMethod3() 

Warum nicht:

  • Haben Sie eine Basisklasse von dem alle benutzerdefinierten Zellklassen erben, die die obige Schnittstelle implementieren (die drei Methoden, die Sie nach dem Entzug einer Zelle verwenden, mit der Möglichkeit, dass sie für jede konkrete Unterklasse überschrieben werden), also einmal aus der Warteschlange und in den Basistyp (I glaube die richtige Umsetzung der Methoden w wird für jede Unterklasse ausgeführt. Der Cast soll nur den Compiler glücklich machen: UITableViewCell hat diese Methoden nicht).

  • Haben Sie einen Switch-Klausel für den Datentyp, der Sie die spezifischen Zellenkennung zu

  • Lassen Sie jede Prototyp Zelle auf die spezifische Klasse auf dem storyobard, und weisen Sie die spezifische Kennung gibt.

Macht es Sinn?

Jetzt, Form, Blick auf Ihren Code, es sieht nicht aus wie Sie wirklich brauchen Unterklassen. Es ist vollkommen in Ordnung, mehrere verschiedene Protoypen der Unterklasse gleichUITableViewCell mit jeweils einem anderen Unteransichtslayout und einem anderen Wiederverwendungsbezeichner zu haben, solange sie alle mit derselben Anzahl und demselben Typ von Unterviews und anderen benutzerdefinierten Eigenschaften/Methoden arbeiten können.

+0

Wenn ich eine TableViewCell-Basisklasse erstelle, hat sie keinen Zugriff auf meine IBOutlet-Sichten in den Unterklassen. Wenn ich also meine "let cell =" - Anweisungen anrufe, wenn diese als Basisklasse umgewandelt werden, können die Basisklassenmethoden die Zellansichten der Unterklassen nicht füllen. Oder bin ich ein Missverständnis? –

+0

Ich denke, wenn Sie die entsprechende Unterklasse für jede Prototypzelle im identify inpector festlegen, instanziiert das Storyboard es wie angefordert. Das Umwandeln in die Basisklasse "konvertiert" es nicht in eine Instanz der Basisklasse (die es in gewissem Sinne bereits ist), aber Sie können 'fillCellWith (article:)' aufrufen, ohne einen Compilerfehler zu haben. Wenn die spezifische Unterklasse die Methode überschreibt, wird die überschriebene Implementierung aufgerufen. Das Outlet-Setup sollte im Quellcode der Zellen-Unterklasse ausgeführt werden. Es handelt sich also um ein Implementierungsdetail, das von Ihrem Tabellenansicht-Controller isoliert ist. –

+0

Und wahrscheinlich verwenden 'dequeueReusableCell (withIdentifier :, für:)' –

-1

Es gibt keine Möglichkeit zu tun, was Sie annehmen. Sie müssen die Klassen einzeln für Ihren Bedarf umsetzen. Oder Sie können eine Basisklasse verwenden, die alle benötigten Methoden implementiert und sie vom Datentyp aufruft.

Verwandte Themen