ios - 添加新内容并刷新 UITableView 会在 Swift 中卡住我的应用程序几秒钟

标签 ios swift uitableview swift3

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

所以我有一个对象数组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 按钮并再次开始输入 - 整个界面卡住了几秒钟,我什至看不到键盘的反馈。我认为问题在于 TableView 必须完全刷新。

我在 Chat 组件中使用上面的界面,因此不仅当用户连续快速键入多条消息时会出现问题,而且当有很多传入消息时也会出现问题。

有什么方法可以加快整个界面的速度,例如在表格 View 底部添加新单元格并避免刷新现有单元格?

与我的 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];
}

关于ios - 添加新内容并刷新 UITableView 会在 Swift 中卡住我的应用程序几秒钟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43764522/

相关文章:

ios - Cordova 上的 Firebase 不会触发 iOS 设备上的通知

ios - 使用 Xcode 11 与 Xcode 10 编译时,NSData 描述和 NSString stringWithFormat 具有不同的返回结果

ios - 当不在 UIViewController 中时,如何触发 segue 以显示特定 View ?

ios - 长按手势识别器仅在手指抬起时触发

swift - 在 Swift 中使用 AVAsynchronousKeyValueLoading

ios - UITableView 部分标题自动高度未正确更新

ios - 如何使用适用于 iOS 的 swift 3 连接到 MEAN stack REST api

ios - swift - 我可以连接到 socket.io 服务器,但我无法发出事件

ios - 当用户点击带有 `UITableView` 的单元格时,在 `UITextField` 上添加自动完成列表/表格

ios - Tableview 搜索栏不显示任何数据并且在我运行时有时会出现一些错误