Как обновить NSTableView без использования -reloadData?

Я новичок в Mac. Я пытаюсь обновить конкретную ячейку в NSTableView без использования -reloadData, как -reloadData обновляет всю таблицу. Я перепробовал все, но все было напрасно. Я пытаюсь сделать что-то похожее на то, что мы делали в CListCtrl в MFC или.NET.

5 ответов

Посмотри на reloadDataForRowIndexes:columnIndexes: метод. Для обновления одной ячейки должно работать следующее:

[yourTable reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row]  
                     columnIndexes:[NSIndexSet indexSetWithIndex:column]];

Это фундаментальное различие между тем, как представления обычно работают в Какао, и тем, как они работают в некоторых других средах. NSTableView выставляет -reloadDataForRowIndexes:columnIndexes: API, как указывает Владимир, но вы заметите отсутствие параметра withObject:.

Это связано с тем, что представления и элементы управления Какао не предназначены для работы в качестве контейнеров данных. Скорее, они предназначены для представления и взаимодействия с данными, которыми управляет какой-либо другой объект модели, обычно через некоторый промежуточный контроллер.

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

Таким образом, несмотря на внешнее сходство во взаимодействии с пользователем, вы, вероятно, захотите пересмотреть то, как вы пишете код для реализации вашего пользовательского интерфейса. В итоге вы получите гораздо более разборчивый код стиля Model-View-Controller; цена заключается в том, что вам нужно будет на самом деле представлять свою модель более тщательно, чем вы могли бы иметь в рамках, которые не требовали такого разделения интересов.

Полный пример использования reloadDataForRowIndexes для обновления всех строк, но только одного столбца:

int col = 2 ;
[self.myTable reloadDataForRowIndexes:
    [NSIndexSet indexSetWithIndexesInRange:
        NSMakeRange(0,self.myTable.numberOfRows)] 
    columnIndexes:
        [NSIndexSet indexSetWithIndex:col]
];

Или все столбцы для одной строки:

int row = 2 ;
[self.myTable reloadDataForRowIndexes:
    [NSIndexSet indexSetWithIndex:row]
columnIndexes:
    [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.myTable.numberOfColumns)]
];

Если ваша строка таблицы достаточно умна, чтобы обновить себя с помощью рисования, вы можете сделать что-то вроде этого. Этот метод ViewController отвечает на сообщение NSNotification исходным объектом, который обновился сам.

Swift 4 код:

class ObjectChooserListViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    @IBOutlet weak var tableView: NSTableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(objectUpdating(_:)), name: NSNotification.Name("ObjectUpdating"), object: nil)
        // more stuff happening
    }

    @objc func objectUpdating(_ notification: NSNotification) {
        guard let object = notification.object as? MyCoolObject else {return}
        guard let row = ObjectManager.shared.getRow(of: object.id) else {return}
        guard let cellView = tableView.view(atColumn: 0, row: row, makeIfNecessary: false) else {return}
        cellView.draw(tableView.frameOfCell(atColumn: 0, row: row))
    }
}

Как правило, обновление всей таблицы через reloadData: это правильный шаблон дизайна. Почему вы против этого? Это из соображений эффективности или вы полагаетесь на таблицу, чтобы сохранить какое-то состояние и перезагрузить все данные, которые мешают этому? Последнее обычно является признаком того, что вам нужно переосмыслить свою архитектуру.

Другие вопросы по тегам