附加新内容和刷新uitableview在Swift中冻结了我的应用程序几秒钟



在我的Swift应用中,我有一个UITableViewUITextView。这个想法很简单,当用户添加文本时 - 应该出现在表视图的底部。

所以我有一个对象SingleMessage的数组:

var messages = [SingleMessage]()

用户将文本添加到UITextView时,我将使用Socket.IO发送消息并接收:

func messageArrived(_ notification: Notification) {
    if let message = (notification as NSNotification).userInfo?["message"] as? SingleMessage {
           DispatchQueue.main.async(execute: { () -> Void in
              messages.append(message)
              self.tview.reloadData()
              self.scrollToBottom()
     )}
    }
}

我的功能scrollToBottom()包含以下代码:

if(self.messages.count > 0) {
        let iPath = IndexPath(row: self.tview.numberOfRows(inSection: 0)-1, section: self.tview.numberOfSections-1)
        self.tview.scrollToRow(at: iPath, at: UITableViewScrollPosition.bottom, animated: false)
    }

然后我有cellForRow功能,可以做很多事情,例如为每个标签设置字体和文本,等等。

override func tableView(_ tview: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tview.dequeueReusableCell(withIdentifier: "chat") as! SingleCommentCell
    if let msg:SingleMessage =  self.messages[(indexPath as NSIndexPath).row] as? SingleMessage {
        .
        .
        .

我的问题是,当我键入某些内容时,请立即按send按钮并再次键入 - 整个接口冻结了几秒钟,我什至没有从键盘上看到反馈。我认为问题是必须完全刷新表观。

我正在使用上面的聊天组件中的界面,因此问题不仅在用户快速键入连续的几条消息时,而且在有许多传入的消息时发生。

是否有任何方法可以加速整个接口,例如,在表视图的底部添加新单元格并避免已经存在的单元格?

与我的UITableViewController相关的其他功能是:

override func tableView(_ tview: UITableView, numberOfRowsInSection section: Int) -> Int {
    return messages.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return UITableViewAutomaticDimension
}

然后我有:

override func viewDidLoad() {
    super.viewDidLoad()
    tview.separatorStyle = UITableViewCellSeparatorStyle.none
    tview.backgroundColor = UIColor.clear
    tview.delegate = self
    tview.dataSource = self
    self.tview.estimatedRowHeight = 100
    NotificationCenter.default.addObserver(self, selector: #selector(ChatView.messageArrived(_:)), name: NSNotification.Name(rawValue: incomingMessage), object: nil)
}

reloadData是一个非常昂贵的操作。它重建了整个桌子。当您想执行这些操作并在更改时刷新单个行时,您最好更好地跟踪模型,使用插入和删除行函数。

一个很好的策略是保持旧模型,生成新模型,然后计算创建,移动或删除的项目集,并为每种情况生成单个表操作。这是一些示例代码:

- (void) setDevicesForKey: (NSString *) propertyKey
                toDevices: (NSArray *) newDevices
{
    NSArray *currentDevices = [self valueForKey: propertyKey];
    NSUInteger tableSection = [self sectionForKey: propertyKey];
    NSIndexSet *indexesOfItemsToRemove = [currentDevices indexesOfObjectsPassingTest: ^BOOL(DeviceItem * itemToCheck, NSUInteger idx, BOOL *stop) {
        return ![newDevices containsObject: itemToCheck];
    }];
    NSIndexSet *indexesOfItemsToAdd = [newDevices indexesOfObjectsPassingTest:^BOOL(DeviceItem *itemToCheck, NSUInteger idx, BOOL *stop) {
        return ![currentDevices containsObject: deviceItem];
    }];
    UITableView *tableView = [self tableView];
    [tableView beginUpdates];
    {
        NSMutableArray *removeIndexPaths = [NSMutableArray array];
        [indexesOfItemsToRemove enumerateIndexesUsingBlock: ^(NSUInteger idx, BOOL *stop) {
            [removeIndexPaths addObject: [NSIndexPath indexPathForItem: idx inSection: tableSection]];
        }];
        [tableView deleteRowsAtIndexPaths: removeIndexPaths withRowAnimation: UITableViewRowAnimationAutomatic];
        NSMutableArray *insertIndexPaths = [NSMutableArray array];
        [indexesOfItemsToAdd enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
            [insertIndexPaths addObject: [NSIndexPath indexPathForItem: idx inSection: tableSection]];
        }];
        [tableView insertRowsAtIndexPaths: insertIndexPaths withRowAnimation: UITableViewRowAnimationAutomatic];
        [newDevices enumerateObjectsUsingBlock: ^(DeviceItem *itemToCheck, NSUInteger idx, BOOL *stop) {
            if([currentDevices containsObject: itemToCheck])
            {
                NSUInteger oldIndex = [currentDevices indexOfObject: ticketToCheck];
                NSUInteger newIndex = [newDevices indexOfObject: ticketToCheck];
                if(oldIndex != newIndex)
                {
                    NSIndexPath *fromIndexPath = [NSIndexPath indexPathForRow: oldIndex inSection: tableSection];
                    NSIndexPath *toIndexPath = [NSIndexPath indexPathForRow: newIndex inSection: tableSection];
                    [tableView moveRowAtIndexPath: fromIndexPath toIndexPath: toIndexPath];
                }
            }
        }];
        [self setValue: newDevices forKey: propertyKey];
    }
    [tableView endUpdates];
}

我建议使用insertRows(at插入行,而不是在不可见的情况下滚动reloadData并滚动。

func messageArrived(_ notification: Notification) {
    if let message = notification.userInfo?["message"] as? SingleMessage {
        DispatchQueue.main.async {
            // if the index path is created before the item is inserted the last row is self.messages.count
            let newIndexPath = IndexPath(row: self.messages.count, section: 0)
            self.messages.append(message)
            self.tableView.insertRows(at: [newIndexPath], with: .automatic)
            if let visiblePaths = self.tableView.indexPathsForVisibleRows, !visiblePaths.contains(newIndexPath) {
                self.tableView.scrollToRow(at: newIndexPath, at: .bottom, animated: false)
            }
        }
    }
}

注意:

可变名称的8个字符的限制已经结束了30多年。
诸如tview之类的名称很难阅读。我正在代码中使用tableView

相关内容

  • 没有找到相关文章

最新更新