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



есть ли способ получить доступ к владению UITableView внутри UITableViewCell?

506   7  

7 ответов:

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

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

вот более приятный способ сделать это, который не зависит от какой-либо конкретной иерархии 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.


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

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

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

Xcode 7 beta, Swift 2.0

это прекрасно работает для меня, на мой взгляд, это не имеет ничего общего с иерархией или любой другой. До сих пор у меня не было проблем с этим подходом. Я использовал это для многих асинхронных обратных вызовов (ex. когда запрос 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)

    }
}

внутри класса представления таблицы, который реализует источник данных и делегат

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 соответственно.

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

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

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

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

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

ячейки.h

 // interface
 id root;

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

ячейки.м

@синтезировать корень;

tableviewcontroller.м

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

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

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

два метода в других ответах: (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 существовать на reuseidentifier, а не на reuseidentifier на tableview, на этом день все реализации, которые используют слабый ссылочный метод, сломаются).

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

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

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

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

Comments

    Ничего не найдено.