Ссылка с UITableViewCell на родительский UITableView?

Есть ли способ получить доступ к собственному UITableView изнутри UITableViewCell?

Ответ 1

Сохраните ссылку weak для таблицыView в ячейке, которую вы установили в -tableView:cellForRowAtIndexPath: вашего файла dataSource.

Это лучше, чем полагаться на self.superview, чтобы всегда быть точным. tableView является хрупким. Кто знает, как Apple может повторно организовать иерархию представлений UITableView в будущем.

Ответ 2

Здесь более удобный способ сделать это, что не зависит от какой-либо конкретной иерархии UITableView. Он будет работать с любой будущей версией iOS при условии, что UITableView не изменяет имя класса вообще. Мало того, что это крайне маловероятно, но если это произойдет, вам все равно придется ретушировать ваш код.

Просто импортируйте указанную ниже категорию и получите свою ссылку с помощью [myCell parentTableView]

@implementation UIView (FindUITableView)

-(UITableView *) parentTableView {
    // iterate up the view hierarchy to find the table containing this cell/view
    UIView *aView = self.superview;
    while(aView != nil) {
        if([aView isKindOfClass:[UITableView class]]) {
            return (UITableView *)aView;
        }
        aView = aView.superview;
    }
    return nil; // this view is not within a tableView
}

@end


// To use it, just import the category and invoke it like so:
UITableView *myTable = [myTableCell parentTableView];

// It can also be used from any subview within a cell, from example
// if you have a UILabel within your cell, you can also do:
UITableView *myTable = [myCellLabel parentTableView];

// NOTE:
// If you invoke this on a cell that is not part of a UITableView yet
// (i.e., on a cell that you just created with [[MyCell alloc] init]),
// then you will obviously get nil in return. You need to invoke this on cells/subviews
// that are already part of a UITableView.


UPDATE
Существует некоторая дискуссия в комментариях о том, является ли сохранение слабых ссылок лучшим подходом. Это зависит от ваших обстоятельств. Прохождение иерархии представлений имеет небольшое ограничение времени исполнения, поскольку вы зацикливаетесь до тех пор, пока не будет идентифицирован целевой UIView. Насколько глубоки ваши взгляды? С другой стороны, сохранение ссылки на каждую ячейку имеет минимальное ограничение памяти (слабая ссылка - это указатель в конце концов), и, как правило, добавление отношений объектов там, где они не нужны, считается плохой практикой проектирования OO по многим причинам, и (см. подробности в комментариях ниже).

Что еще более важно, сохранение ссылок на таблицы внутри ячеек добавляет сложность кода и может привести к ошибкам, поскольку UITableViewCells можно использовать повторно. Не случайно, что UIKit не включает свойство cell.parentTable. Если вы определите свой собственный, вы должны добавить код для его управления, и если вы не сделаете этого эффективно, вы можете ввести утечки памяти (т.е. Ячейки живут за время жизни их таблицы).

Поскольку обычно вы будете использовать вышеприведенную категорию, когда пользователь взаимодействует с ячейкой (выполняется для одной ячейки), а не при раскладке таблицы в [tableView:cellForRowAtIndexPath:] (выполняется для всех видимых ячеек), время выполнения стоимость должна быть незначительной.

Ответ 3

Xcode 7 beta, Swift 2.0

Это отлично работает для меня, по-моему, это не имеет ничего общего с иерархией или чем-то еще. До сих пор у меня не было проблем с этим подходом. Я использовал это для многих асинхронных обратных вызовов (например, когда выполняется запрос API).

Класс TableViewCell

class ItemCell: UITableViewCell {

    var updateCallback : ((updateList: Bool)-> Void)? //add this extra var

    @IBAction func btnDelete_Click(sender: AnyObject) {
        let localStorage = LocalStorage()
        if let description = lblItemDescription.text
        {
            //I delete it here, but could be done at other class as well.
            localStorage.DeleteItem(description) 
        }
        updateCallback?(updateList : true)

    }
}

Внутри класса представления таблицы, который реализует DataSource и Delegate

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: ItemCell = self.ItemTableView.dequeueReusableCellWithIdentifier("ItemCell") as! ItemCell!
    cell.updateCallback = UpdateCallback //add this extra line
    cell.lblItemDescription?.text = self.SomeList[indexPath.row].Description
    return cell
}

func UpdateCallback(updateTable : Bool) //add this extra method
{
    licensePlatesList = localStorage.LoadNotificationPlates()
    LicenseTableView.reloadData()
}

Конечно, вы можете поместить любую переменную в updateCallback и соответственно изменить ее в tableView.

Кто-то, возможно, захочет сказать мне, если он будет полезен, но, чтобы быть уверенным.

Ответ 4

Вы должны добавить ссылку обратно в UITableView при создании ячейки представления таблицы.

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

Альтернативный подход, если вы подключаете действия, заключается в создании ячеек в IB, с контроллером представления таблиц в качестве владельца файла - затем подключите кнопки в ячейке к действиям в контроллере табличного представления. Когда вы загружаете ячейку xib с помощью loadNibNamed, пройдите в контроллере представления, когда владелец и действия кнопки будут подключены обратно к контроллеру табличного представления.

Ответ 5

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

cell.h

 // interface
 id root;

 // propery 
 @property (nonatomic, retain) id root;

cell.m

@synthesize root;

tableviewcontroller.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  // blah blah, traditional cell declaration
  // but before return cell;
  cell.root = tableView;
}

Теперь вы можете вызвать любой из методов tableview из вашей ячейки, используя корневую переменную. (например, [root reloadData]);

А, возвращает меня в старые добрые времена программирования вспышки.

Ответ 6

В других ответах есть два метода: (A) сохранить ссылку на таблицу или (B) просмотреть суперпредставления.

Я бы всегда использовал что-то вроде (A) для объектов модели и (B) для ячеек таблицы.

ячейки

Если вы имеете дело с UITableViewCell, то, AFAIK, вы должны либо иметь UITableView под рукой (скажем, вы находитесь в методе делегата таблицы), либо иметь дело с видимой ячейкой, которая находится в иерархии представления. В противном случае, вы вполне можете делать что-то не так (обратите внимание на "может хорошо").

Ячейки широко используются повторно, и если у вас есть такой, который не виден, то единственная реальная причина существования ячейки - это оптимизация производительности iOS UITableView (более медленная версия iOS вышла бы и, надеюсь, освободила ячейку, когда она вышла за пределы экрана). ) или потому что у вас есть конкретная ссылка на него. Я думаю, это, вероятно, причина того, что ячейки таблицы не наделены методом экземпляра tableView.

Таким образом (B) дает правильный результат для всех iOS до сих пор и для всех будущих, пока они радикально не изменят работу представлений.

Хотя, чтобы избежать многократного написания обобщенного кода, я бы использовал это:

+ (id)enclosingViewOfView:(UIView *)view withClass:(Class)returnKindOfClass {
  while (view&&![view isKindOfClass:returnKindOfClass]) view=view.superview;
  return(view);
}

и удобный метод:

+ (UITableView *)tableForCell:(UITableViewCell *)cell {
  return([self enclosingViewOfView:cell.superview withClass:UITableView.class]);
}

(или категории, если хотите)

Кстати, если вы обеспокоены влиянием цикла с примерно 20 итерациями такого размера на производительность вашего приложения, не надо.

модели

Если вы говорите об объекте модели, отображаемом в ячейке, то определенно эта модель может/должна знать о своей родительской модели, которая может использоваться для поиска или запуска изменений в таблице (таблицах), которые могут моделировать ячейки. отображаться в. Это похоже на (A), но менее хрупкое с будущими обновлениями iOS (например, однажды они могут заставить кэш повторного использования UITableViewCell существовать для каждого повторного идентификатора, а не для повторного идентификатора для табличного представления), в тот день все реализации, которые используют слабые эталонный метод сломается).

Этот метод модели будет использоваться для изменений данных, отображаемых в ячейке (т.е. Изменения модели), поскольку изменения будут распространяться везде, где отображается модель (например, какой-то другой UIViewController где-то еще в приложении, регистрация,...)

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

В любом случае, используйте unit тест, а не предполагайте, что на первый взгляд более чистый код работает только при обновлении iOS.

Ответ 7

UITableView *tv = (UITableView *) self.superview.superview;
UITableViewController *vc = (UITableViewController *) tv.dataSource;