Как получить indexPath UITableViewCell из ячейки?

Как мне из ячейки получить indexPath в UITableView?

Я искал вокруг переполнения стека и Google, но вся информация находится наоборот. Есть ли способ получить доступ к superView/UITableView, а затем найти ячейку?

Дополнительная информация о контексте: у меня есть два класса, один называется Cue, а другой называется CueTableCell (который является подклассом UITableViewCell). CueTableCell является визуальным представлением Cue (оба класса имеют указатели друг на друга). Cue объектов находятся в связанном списке, и когда пользователь выполняет определенную команду, необходимо выбрать визуальное представление (CueTableCell) следующих Cue. Таким образом, класс Cue вызывает метод select для следующего Cue в списке, который извлекает UITableView из cell и вызывает свой selectRowAtIndexPath:animated:scrollPosition:, для чего ему нужен indexPath из UITableViewCell.


person sinθ    schedule 29.03.2013    source источник
comment
Как и ваш другой вопрос о получении UITableView из ячейки - почему? Это похоже на запах кода плохого дизайнерского решения - не так много законных вариантов использования ячейки, чтобы знать, либо ее indexPath, либо то, находится ли она на экране или нет.   -  person Paul.s    schedule 30.03.2013
comment
Я согласен с комментарием Paul.s. Вы должны указать, почему вы хотите это сделать, потому что то, что вы пытаетесь сделать, вероятно, является плохой идеей.   -  person rdelmar    schedule 30.03.2013
comment
@Paul.s Я опубликовал дизайн своей программы в вопросе. Это может быть плохой практикой программирования, и в этом случае, если бы вы могли предложить альтернативу, это было бы очень полезно. Я очень новичок в какао и относительно новичок в программировании в целом.   -  person sinθ    schedule 30.03.2013
comment
Стоит отметить, что indexPathsForVisibleRows существует — это очень важно, когда вы хотите знать, где вы находитесь в прокрутке.   -  person Fattie    schedule 29.07.2019


Ответы (12)


NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

Полезно прочитать документацию UITableView, даже если некоторые считают ее спорной (см. комментарии ниже).

Ячейка не имеет права знать, какой у нее индексный путь. Контроллер должен содержать любой код, который манипулирует элементами пользовательского интерфейса на основе модели данных или изменяет данные на основе взаимодействий с пользовательским интерфейсом. (См. MVC.)

person Mundi    schedule 29.03.2013
comment
Это поможет, если вы прочитаете вопрос. Это из UITableViewCell, у которого нет свойства tableView (и, судя по всему, не должно). - person voidref; 03.04.2013
comment
@voidref Это также помогает подумать над вопросом ;-). Ячейка не имеет права знать, какой у нее индексный путь. Так что этот код должен быть в контроллере. Справочную информацию о MVC см. в разделе Основные компетенции Cocoa. . - person Mundi; 03.04.2013
comment
Достаточно справедливо, но тогда ваш первоначальный ответ должен был объяснить это. - person shim; 17.12.2013
comment
@shim Я не согласен. Это измерение не было очевидным с самого начала. - person Mundi; 18.12.2013
comment
Неважно, было ли с самого начала очевидно, что человеку нужен правильный ответ. - person jdog; 20.02.2014
comment
Не отвечает на исходный вопрос. Бывают случаи, когда ячейке необходимо знать свой путь. Например, если вы реализовали какую-либо форму действия смахивания в ячейке подкласса, вам может потребоваться сообщить родительскому представлению, какая ячейка в данный момент пролистывается. Один из способов заключается в том, чтобы метод в parentView перебирал ячейки tableView и проверял iVar, который был установлен в ячейке. Лучшим способом было бы заставить ячейку информировать parentView о своем indexPath с помощью метода делегата... и, следовательно, ячейка должна знать свой indexPath. Итак, Мунди, лучше ответить на вопрос, а затем изложить свою точку зрения. - person wuf810; 05.04.2014
comment
Очевидно, что да, MVC можно использовать, передав ячейку обратно, но если вы передаете ячейку, почему бы не передать indexPath! - person wuf810; 05.04.2014
comment
Путь индекса является связующим звеном между ячейками и моделью данных, поэтому он принадлежит контроллеру. Длинный комментарий выше фактически неверен. @ wuf810 ... поскольку контроллер знает взаимосвязь между ячейкой и путем индекса, ячейка не знает (и не должна). - person Mundi; 29.07.2014
comment
@Mike Майк, я думаю, что эти два ответа не по теме. - person Mundi; 26.07.2015
comment
@Mundi Спасибо за отзыв о моем комментарии. - person Mike; 26.07.2015
comment
Поддержу этот разговор спустя 5 лет. Технически Мунди прав, ячейка не должна знать индексный путь. К сожалению, indexPathForCell вернет nil, если ячейка еще не была отображена, поэтому вы не можете полагаться на этот метод. Например, если ячейка вызывает метод делегата до того, как ячейка была возвращена из cellForRowAt, indexPathForCell даст вам ноль. Таким образом, ячейка должна вернуть вам модель представления, с которой она была настроена. Но тогда это может также вернуть вам и indexPath. - person Lord Zsolt; 01.07.2020

Попробуйте это из своего UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview indexPathForCell: self];

РЕДАКТИРОВАТЬ: кажется, это не работает на iOS 8.1.2 и более поздних версиях. Спасибо Крису Принсу за указание на это.

person Pepper    schedule 28.11.2013
comment
В iOS 8.1.2 суперпредставление ячейки табличного представления имеет тип UITableViewWrapperView. Супервизор этого типа имеет табличное представление. Но я думаю, что мы ступаем на опасную почву здесь... - person Chris Prince; 13.01.2015
comment
Все это возвращается к ячейке, которой не нужно знать, какой у нее индексный путь. аргумент. Доступ к superview почти всегда является хаком, и неудивительно, что через некоторое время он не работает. - person fatuhoku; 29.03.2015
comment
Совершенно верно, фатухоку, ячейка не в том, чтобы знать индексный путь - person Yahya Alshaar; 12.02.2018

Вы можете попробовать этот простой совет:

в вашем UITableViewCell классе:

@property NSInteger myCellIndex; //or add directly your indexPath 

и по вашему методу cellForRowAtIndexPath:

...
[cell setMyCellIndex : indexPath.row]

теперь вы можете получить индекс своей ячейки в любом месте

person AITAALI_ABDERRAHMANE    schedule 06.10.2015
comment
Вам нужно не забыть обновить эту информацию вручную после изменения порядка или удаления ячеек. - person konrad; 12.03.2017

Обращаясь к тем, кто говорит "это плохая идея", в моем случае мне нужно, чтобы у меня была кнопка на моем UITableViewCell, при нажатии которой происходит переход к другому представлению. Поскольку это не выделение самой ячейки, [self.tableView indexPathForSelectedRow] не работает.

Это оставляет мне два варианта:

  1. Сохраняйте объект, который мне нужно передать в представление, в самой ячейке таблицы. Хотя это сработает, это лишит меня смысла иметь NSFetchedResultsController, потому что я нет хотите хранить все объекты в памяти, особенно если таблица длинная.
  2. Получить элемент из контроллера выборки, используя индексный путь. Да, кажется уродливым, что мне приходится вычислять NSIndexPath с помощью хака, но в конечном счете это дешевле, чем хранение объектов в памяти.

indexPathForCell: - правильный метод для использования, но вот как я бы это сделал (предполагается, что этот код реализован в подклассе UITableViewCell:

// uses the indexPathForCell to return the indexPath for itself
- (NSIndexPath *)getIndexPath {
    return [[self getTableView] indexPathForCell:self];
}

// retrieve the table view from self   
- (UITableView *)getTableView {
    // get the superview of this class, note the camel-case V to differentiate
    // from the class' superview property.
    UIView *superView = self.superview;

    /*
      check to see that *superView != nil* (if it is then we've walked up the
      entire chain of views without finding a UITableView object) and whether
      the superView is a UITableView.
    */
    while (superView && ![superView isKindOfClass:[UITableView class]]) {
        superView = superView.superview;
    }

    // if superView != nil, then it means we found the UITableView that contains
    // the cell.
    if (superView) {
        // cast the object and return
        return (UITableView *)superView;
    }

    // we did not find any UITableView
    return nil;
}

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

person mikeho    schedule 25.03.2014

  1. Поместите слабое свойство tableView в файл ячейки .h, например:

    @property (weak,nonatomic)UITableView *tableView;

  2. Назначьте свойство в методе cellForRowAtIndex, например:

    cell.tableView = tableView;

  3. Теперь, когда вам нужен indexPath ячейки:

    NSIndexPath *indexPath = [cell.tableView indexPathForCell:cell];

person Chanchal Raj    schedule 23.04.2015
comment
Это работает, потому что мы храним только указатель на сам tableView, однако надежен ли indexPathForCell? Я думал, что это обеспечивает indexPath только видимых ячеек, нет? - person jcpennypincher; 12.05.2015

Для быстрого

let indexPath :NSIndexPath? = (self.superview.superview as! UITableView)?.indexPathForCell(self)
person Gevorg Ghukasyan    schedule 02.06.2016

Ответ на этот вопрос мне очень помог.

Я использовал NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];

sender в моем случае был UITableViewCell и происходит от метода prepareForSegue.

Я использовал это, потому что у меня нет TableViewController, но был UITableView property outlet

Мне нужно было узнать название Cell и, следовательно, нужно было знать его indexPath.

Надеюсь, это поможет любому!

person Cescy    schedule 14.02.2014

В iOS 11.0 вы можете использовать UITableView.indexPathForRow(at point: CGPoint) -> IndexPath?:

if let indexPath = tableView.indexPathForRow(at: cell.center) {
    tableView.selectRow
    (at: indexPath, animated: true, scrollPosition: .middle)
}

Он получает центральную точку ячейки, а затем tableView возвращает indexPath, соответствующий этой точке.

person banan3'14    schedule 06.11.2017

попробуйте это (это работает, только если tableView имеет только один раздел и все ячейки имеют одинаковую высоту):

//get current cell rectangle relative to its superview
CGRect r = [self convertRect:self.frame toView:self.superview];

//get cell index
int index = r.origin.y / r.size.height;
person m.eldehairy    schedule 09.08.2015

Swift 3.0 и выше-

Если нужно получить индексный путь из пользовательской ячейки,

if let tableView = self.superview as? UITableView{
    if let indexPath = tableView.indexPath(for: self){
        print("Indexpath acquired.")
    }else{
        print("Indexpath could not be acquired from tableview.")
    }
}else{
    print("Superview couldn't be cast as tableview")
}

Хорошей практикой является высматривание случаев сбоя.

person Natasha    schedule 20.02.2021

Попробуйте это из своего UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview.superview indexPathForCell:self];
person Yogesh Kumar    schedule 26.05.2015

Свифт 4.х

Чтобы предоставить доступ к моей ячейке, я сделал что-то вроде этого:

У меня есть расширение UIView:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

А потом... в моей камере Класс:

class SomeCell: UITableViewCell {

    func someMethod() {
        if let myViewController = self.parentViewController as? CarteleraTableViewController {
            let indexPath : IndexPath = (myViewController.tableView).indexPath(for: self)!
            print(indexPath)
        }
    }
}

Вот и все.

С наилучшими пожеланиями.

person Andres Paladines    schedule 03.08.2018