2015-12-11 19 views
11

Ich habe eine ziemlich komplizierte Tabellenansicht Setup und ich beschloss, eine Blockstruktur zum Erstellen und Auswählen der Zellen zu verwenden, um die zukünftige Entwicklung und Änderungen zu vereinfachen.EXC_BAD_ACCESS beim Zugriff auf Wert in Block

Die Struktur Ich verwende sieht wie folgt aus:

var dataSource: [(
    cells:[ (type: DetailSection, createCell: ((indexPath: NSIndexPath) -> UITableViewCell), selectCell: ((indexPath: NSIndexPath) ->())?, value: Value?)], 
    sectionHeader: (Int -> UITableViewHeaderFooterView)?, 
    sectionFooter: (Int -> UITableViewHeaderFooterView)? 
)] = [] 

kann ich dann die Tabelle in einer Setup-Funktion einrichten und meine Delegatmethoden machen ziemlich einfach

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = dataSource[indexPath.section].cells[indexPath.row].createCell(indexPath:indexPath) 
    return cell 
} 

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return dataSource[section].cells.count 
} 

func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
    return dataSource.count 
} 

ich gemacht habe ein ähnliches Setup vorher in einem anderen TVC

var otherVCDataSource: [[ (type: DetailSection, createCell: ((indexPath: NSIndexPath) -> UITableViewCell), selectCell: ((indexPath: NSIndexPath) ->())?)]] = [] 

Diese Lösung hat gut funktioniert.

Die aktuelle dataSource mit dem AbschnittHead und Footer gibt mir jedoch ein EXC_BAD_ACCESS jedes Mal, wenn ich versuche, auf den IndexPath in einem der createCell Blöcke zuzugreifen.

createCell: { 
    (indexPath) in 
    let cell:CompactExerciseCell = self.tableView.dequeueReusableCellWithIdentifier(self.compactExerciseCellName, forIndexPath:indexPath) as! CompactExerciseCell 
    cell.nameLabel.text = "\(indexPath.row)" 
    cell.layoutMargins = UIEdgeInsetsZero 
    return cell 
} 

Die App stürzt immer auf

self.tableView.dequeueReusableCellWithIdentifier(self.compactExerciseCellName, forIndexPath:indexPath) 

Was bin ich hier? Warum kann ich in der neuen Struktur nicht auf den Indexpfad zugreifen, wenn er in der alten Struktur funktioniert? Was ist in der Speicherverwaltung zwischen diesem Tupel und dem Array anders?

UPDATE:

So hatte ich eine Frist zu halten, und ich musste schließlich aufgeben und die Datenstruktur überarbeitet.

My ersten Versuch war stattdessen die indexPath als Parameter des Sendens der Reihen- und senden Abschnitt und einen indexPath innerhalb des Block neu zu erstellen. Dies funktionierte für alles innerhalb der Datenstruktur, aber wenn ich einen anderen View-Controller auf einen Zellklick drückte, bekam ich einen weiteren extrem seltsamen Crash (irgendeinen Malloc-Fehler, der merkwürdig ist, wenn ich ARC benutze), wenn Zellen in der nächsten VC aus der Warteschlange genommen wurden.

Ich habe versucht, auch bei diesem Absturz herumzuheulen, aber es gab keine Zeit mehr dafür, also musste ich zu einer anderen Lösung übergehen.

Anstelle dieses Tupel-Arrays [([] ,,)] habe ich zwei Arrays erstellt; eine für die Zellen und eine für die Kopf- und Fußzeilen. Diese Struktur löste das Problem des IndexPath-Absturzes, aber ich hatte immer noch das Problem in der nächsten VC, dass nicht abstürzte beim Entfernen der Zellen.

Die endgültige Lösung oder Vermeidung des Problems war mit dieser Erweiterung die Zelle Schöpfer und Wähler „sicher“ zuzugreifen:

extension Array { 
    subscript (safe index: Int) -> Element? { 
     return indices ~= index ? self[index] : nil 
    } 
} 

im Grunde die Erklärung Rückkehr in den Tableview delegieren Funktionen sieht dann wie folgt aus:

return dataSource[safe:indexPath.section]?[safe:indexPath.row]?.createCell?(indexPath: indexPath) 

statt

return dataSource[indexPath.section][indexPath.row].createCell?(indexPath: indexPath) 

Ich kann nicht sehen, wie es zum nächsten VC macht, da die Zelle nicht einmal existieren sollte, wenn ein Problem mit der Ausführung von nil oder nach nicht existierenden Indizes in der Datenstruktur bestand, aber dies löste das Problem, das ich war mit der Auslagerung von Zellen in der nächsten VC.

Ich habe immer noch keine Ahnung, warum die Änderung der Datenstruktur und die sichere Erweiterung für Werte von einem Array hilft und wenn jemand eine Idee hat, würde ich mich freuen, es zu hören, aber ich kann zu diesem Zeitpunkt nicht mehr experimentieren Lösung. Meine Vermutung ist, dass der sichere Zugriff der Werte die Werte irgendwie neu zugewiesen hat und sie davon abgehalten hat, freigegeben zu werden. Vielleicht hielt das Tupel den Compiler davon ab, zu verstehen, dass die Werte im Speicher bleiben sollten, oder vielleicht habe ich irgendwo nur einen Geist in meinem Code. Ich hoffe, eines Tages kann ich zurückgehen und es genauer untersuchen ...

+0

wahrscheinlich stürzt die App in dieser Zeile ab, weil die resultierende Zelle null ist, nicht weil Ihr IndexPfad nicht zugänglich ist. – user3441734

+0

Zelle war nicht Null. Ich habe es umgangen, indem ich stattdessen Zeile und Abschnitt gesendet habe und den indexPath im Block erstellt habe, aber es ist so eine schreckliche Lösung – Moriya

+0

hm ... das ist wirklich interessant, ich kann es nicht reproduzieren. Da IndexPath der Referenztyp ist, muss der Wert aus dem umgebenden Bereich erfasst werden. Haben Sie versucht, auf Ihren IndexPath zuzugreifen, bevor Sie die Zelle aus der Warteschlange genommen haben? simple print (indexPath) könnte hilfreich sein, um zu verstehen, was dort falsch ist ... – user3441734

Antwort

-1

Sie müssen Ihre Tabelle Tabellenzelle für bestimmte Zelle Idntifier in Viewdidload registrieren. z. tableview.registerNib(UINib(nibName: "cell_nib_name", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "cell_identifier");

für deque Zelle

let cell:CompactExerciseCell = self.tableView.dequeueReusableCellWithIdentifier(self.compactExerciseCellName, forIndexPath:indexPath) as! CompactExerciseCell

wie diese.

+0

Wie im Kommentar erwähnt, sind die Zellen registriert. Das Problem liegt im Zugriff von indexPath. Ich habe das Problem gelöst, indem ich den indexPath aus Zeile und Abschnitt im Block neu erstellt habe. – Moriya

0

Dies ist keine Antwort auf die Frage, sondern eine Abhilfe, wenn jemand in diesem Loch endet und muss raus:

Inbetriebnahme diese Erweiterung für Array:

extension Array { 
    subscript (safe index: Int) -> Element? { 
     return indices ~= index ? self[index] : nil 
    } 
} 

Und dann in die Tabellenansicht delegieren Funktionen verwenden, um die Erweiterung wie diese

let cell = dataSource[safe:indexPath.section]?[safe:indexPath.row]?.createCell?(indexPath: indexPath) 

Wenn dies nicht entfernen funktioniert das Tupel aus der Datenstruktur, und Sie sollten eine funktionierende Lösung haben.

Ich wünsche Ihnen mehr Glück mit diesem Problem als ich hatte.

Verwandte Themen