EXC_BAD_ACCESS при доступе к значению в блоке

У меня довольно сложная настройка табличного представления, и я решил использовать блок-структуру для создания и выбора ячеек, чтобы упростить будущую разработку и изменения.

Структура, которую я использую, выглядит так:

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

Затем я могу настроить таблицу в функции настройки и сделать мои методы делегатов довольно простыми

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
}

Я сделал аналогичную настройку раньше в другом TVC

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

Это решение отлично поработало.

Однако текущий источник данных с секцией Head и Footer, однако, дает мне EXC_BAD_ACCESS каждый раз, когда я пытаюсь получить доступ к indexPath в одном из блоков createCell.

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
}

Приложение всегда сбой на

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

Что мне здесь не хватает? Почему я не могу получить доступ к indexPath в новой структуре, когда он отлично работает в старой структуре? Чем отличается управление памятью между этим кортежем и массивом?

UPDATE:

Итак, у меня был крайний срок, и я, наконец, должен был отказаться и переработать структуру данных.

Первая попытка заключалась вместо отправки indexPath в качестве параметра отправить строку и раздел и перестроить indexPath внутри блока. Это работало на все, что находится внутри структуры данных, но если я нажал на другой контроллер вида на ячейку, я получил еще один чрезвычайно странный сбой (некоторая ошибка malloc, которая является странной, когда я использую ARC) при удалении ячеек в следующем VC.

Я тоже пытался копаться в этом крахе, но больше не было времени тратить на это, поэтому мне пришлось перейти к другому решению.

Вместо этого tuple-array [([],)] я сделал два массива; один для ячеек и один для верхних и нижних колонтитулов. Эта структура устранила проблему сбой indexPath, но у меня все еще была проблема в следующем VC, что не прекращал сбой при удалении ячеек.

Окончательным решением или обходным путем было обращение к создателю ячейки и селектору "безопасно" с этим расширением:

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

в основном оператор return в функциях делегата tableView выглядит следующим образом:

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

вместо

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

Я не вижу, как это имеет значение для следующего VC, поскольку ячейка не должна даже существовать, если возникла проблема с выполнением нулевого значения или поиск не существующих индексов в структуре данных но это все еще решило проблему, с которой я столкнулся с деактивацией ячеек в следующем VC.

Я до сих пор не знаю, почему изменение структуры данных и безопасного расширения для получения значений из массива помогает, и если у кого-то есть идея, я был бы счастлив услышать это, но я не могу в это время больше экспериментировать с решением, Я предполагаю, что безопасный доступ к значениям каким-то образом перераспределил значения и не позволил им освободиться. Возможно, кортеж не дал компилятору понять, что значения должны храниться в памяти или, может быть, у меня просто есть призрак в моем коде где-нибудь. Надеюсь, когда-нибудь я смогу вернуться и разобраться в нем более подробно...

Ответ 1

Это НЕ ответ на вопрос, а скорее обходной путь, если кто-то попадает в эту дыру и должен выйти:

Сначала используйте это расширение для массива:

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

И затем в представлении таблицы функции делегата используют расширение, подобное этому

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

Если это не сработает, удалите кортеж из структуры данных и у вас должно получиться рабочее решение.

Я желаю вам удачи в этом вопросе, чем я.

Ответ 2

вам нужно зарегистрировать ячейку tableview для определенного идентификатора ячейки в viewdidload. например. tableview.registerNib(UINib(nibName: "cell_nib_name", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "cell_identifier");

для ячейки deque

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

как это.