TableView的数据不完整 [英] TableView gets laggy with data

查看:88
本文介绍了TableView的数据不完整的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我面临一个问题

重新加载/添加行几次后,表视图变慢(响应于滚动,点击变慢)

A table view gets slower (responses slower to scrolling, tapping) after reloading/adding rows for a couple of times

因此,用户登录后,该应用将下载10个"WorldMessages" .它已加载到此表视图中.

So after the user logs in, the app downloads 10 "WorldMessages". It is loaded into this table view.

如果用户向下滚动,它将调用一个加载更多10的函数:loadOlderOwnWorldMessages()

If the user scrolls down, it calls a function which loads more 10: loadOlderOwnWorldMessages()

每个单元格都有tapGestureRecognizer + longPressGestureRecognizer

Each cell has a tapGestureRecognizer + longPressGestureRecognizer

我不得不提到,如果用户重新加载tableView,那么它将清除数据并仅再次加载前10个WorldMessages

And I have to mention that If the user reloads the tableView, then it clears the data and loads only the first 10 WorldMessages again

问题

我不知道为什么,但是例如,如果我重新加载tableView 50次,并且每次向下滚动一次或多次,则tableView会变慢.

I don't know why, but for example, if I reload the tableView 50 times and every time I do scroll down a bit or more, then the tableView gets slow.

也许是因为点击/长按手势识别器或约束?

Maybe because of the tap/long press gesture recognizers, or constraints?

应用看起来像这样:

视频延迟后:

https://www.youtube.com/watch?v=65NkjS-Kz3M

(如果我终止了该应用程序并再次将其打开,则它可以再次正常运行,直到我重新加载了几次)

代码:

//不是全部代码,我删除了很多不重要的行(例如重载函数等

// It's not the whole code, I deleted lots of lines of it that were not important (like the reload functions, and etc

class ProfileViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITabBarDelegate {

    // Classes
    let handleData = HandleData()
    let handleResponses = HandleResponses()
    let worldMessagesFunctions = WorldMessagesFunctions()
    let profileFunctions = ProfileFunctions()

    // View Objects
    @IBOutlet var tableView : UITableView!

    // Variables
    var userWorldMessages = [WorldMessage]()
    var lastContentOffsetY : CGFloat?

    var currentSelectedWorldMessageIndexPath : IndexPath?

    // Main Code
    override func viewDidLoad() {
        super.viewDidLoad()

        userWorldMessages = ownWorldMessages.shared.worldMessages
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
       return userWorldMessages.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileWorldMessageCell", for: indexPath) as! ProfileWorldMessageCell

        let worldMessage = userWorldMessages[indexPath.row]

        cell.worldMessageData = worldMessage

        cell.messageLabel.text = worldMessage.message

        if let image = UIImage(named: "bubble") {
            let h = image.size.height / 2
            let w = image.size.width / 2
            cell.bubbleImageView.image = image
                .resizableImage(withCapInsets:
                    UIEdgeInsetsMake(h, w, h, w),
                                resizingMode: .stretch).withRenderingMode(.alwaysTemplate)

            cell.bubbleImageView.tintColor = appColors.worldMessageBubble

        }

        let calendar = NSCalendar.current
        let date = Date(timeIntervalSince1970: Double(worldMessage.leftTime))
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US")
        var dateFormat = "yyyy MMM dd"
        if calendar.isDateInToday(date) {
            // Today
            dateFormat = "HH:mm"
            dateFormatter.string(from: date)
        } else if (calendar.date(byAdding: .weekOfYear, value: -1, to: Date())! < date){
            // This last 7 days
            dateFormat = "EEEE HH:mm"
        } else if (calendar.date(byAdding: .month, value: -12, to: Date())! < date){
            // This year
            dateFormat = "MMM dd"
        } else {
            dateFormat = "yyyy MMM dd"
        }
        dateFormatter.dateFormat = dateFormat
        let strDate = dateFormatter.string(from: date)

        cell.timeLabel.text = strDate

        cell.commentsButton.setTitle("\(worldMessage.comments!) comments", for: .normal)
        cell.likesButton.setTitle("\(worldMessage.likes!) likes", for: .normal)

        // tapped
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(bubbleTappedHandler))
        cell.bubbleButton.addGestureRecognizer(tapGestureRecognizer)
        cell.bubbleButton.isUserInteractionEnabled = true

        // long pressed
        let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(bubbleLongPressHandler))
        longPressGestureRecognizer.minimumPressDuration = 0.5
        cell.addGestureRecognizer(longPressGestureRecognizer)
        cell.isUserInteractionEnabled = true

        return cell
    }
    var cellHeights: [IndexPath : CGFloat] = [:]
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cellHeights[indexPath] = cell.frame.size.height

        if indexPath.row == UserWorldMessagesStore.shared.worldMessages.count - 1 && userWorldMessagesCanLoadMore == true {
            loadOlderOwnWorldMessages()
        }
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if cellHeights[indexPath] != nil {
            return CGFloat(Float(cellHeights[indexPath] ?? 0.0))
        }
        else {
            return UITableViewAutomaticDimension
        }
    }
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if (lastContentOffsetY != nil){
            tableView.setContentOffset(CGPoint(x: 0, y: lastContentOffsetY!), animated: false)
        }
    }



    func loadOlderOwnWorldMessages(){
        profileFunctions.loadOlderOwnWorldMessages(startIndex: (userWorldMessages.count)) { response, newUserWorldMessages in
            if let response = response {
                if response.type == 1 {
                    DispatchQueue.main.async(execute: {() -> Void in
                        if newUserWorldMessages != nil {

                            var insertRows : [IndexPath] = []
                            var fromIndex = UserWorldMessagesStore.shared.worldMessages.count - 1
                            for worldMessage in newUserWorldMessages! {
                                UserWorldMessagesStore.shared.worldMessages.append(worldMessage)
                                insertRows.append(IndexPath(row: fromIndex, section: 1))
                                fromIndex += 1
                            }
                            self.userWorldMessages = UserWorldMessagesStore.shared.worldMessages

                            self.tableView.beginUpdates()
                            self.tableView.insertRows(at: insertRows, with: .automatic)
                            self.tableView.endUpdates()


                        }

                        })
                } else {
                    DispatchQueue.main.async(execute: {() -> Void in
                        self.handleResponses.displayError(title: response.title, message: response.message)
                    })
                }
            }
        }
    }

    @objc func bubbleTappedHandler(sender: UITapGestureRecognizer, should: Bool) {
        let touchPoint = sender.location(in: self.tableView)
        if let indexPath = tableView.indexPathForRow(at: touchPoint) {
            if indexPath == currentSelectedWorldMessageIndexPath {
                // it was already selected, so deselect it

                deselectCurrentSelectedWorldMessage()
            } else {
                // select new one, deselect old one if was selected

                if (currentSelectedWorldMessageIndexPath != nil){
                    deselectCurrentSelectedWorldMessage()
                }

                selectWorldMessage(indexPath: indexPath)
            }
        }
    }
    func selectWorldMessage(indexPath: IndexPath) {

        tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
        currentSelectedWorldMessageIndexPath = indexPath

        if let cell = tableView.cellForRow(at: indexPath) as? ProfileWorldMessageCell {

            // Change some constraints
            cell.messageLabelTopConstraint.constant = 14
            cell.messageLabelBottomConstraint.constant = 14
            UIView.animate(withDuration: 0.15, animations: {
                self.view.layoutIfNeeded()
                self.tableView.beginUpdates()
                self.tableView.endUpdates()
            }, completion: nil)
        }
    }
    @objc func deselectCurrentSelectedWorldMessage(){
        UIMenuController.shared.setMenuVisible(false, animated: true)
        if (currentSelectedWorldMessageIndexPath == nil){
            return
        }
        let indexPath = currentSelectedWorldMessageIndexPath!

        if let cell = tableView.cellForRow(at: indexPath) as? ProfileWorldMessageCell {

            // Change back some constraints
            cell.messageLabelTopConstraint.constant = 10
            cell.messageLabelBottomConstraint.constant = 10
            UIView.animate(withDuration: 0.15, animations: {
                self.view.layoutIfNeeded()
                self.tableView.beginUpdates()
                self.tableView.endUpdates()
            }, completion: nil)
        }

        currentSelectedWorldMessageIndexPath = nil
    }

    @objc func bubbleLongPressHandler(sender: UILongPressGestureRecognizer, should: Bool) {
        // Show options like copy, delete etc.
    }



}

推荐答案

您的cellForRow函数有些错误非常:

  • 这些单元已被重用,而您忽略了这一事实.每次调用cellForRow时,您都将创建手势识别器的新实例,并且当单元被重用时,您将添加另一个实例.这意味着,如果您的单元已被重复使用了50次,它将添加50个手势识别器.您只能创建一次手势识别器
  • 您每次创建一个DateFormatter并设置其dateFormat属性,这实际上是非常昂贵的过程.相反,您应该为每种日期格式设置一个静态的formatter实例
  • the cells are reused, and you are ignoring that fact. You are creating new instances of gesture recognizers each time cellForRow is called, and when cell is reused you are adding yet another one. That means that if your cell had been reused for 50th time, it will have 50 gesture recognizers added. You should create your gesture recognizers only once
  • You create a DateFormatter and set its dateFormat property each time, and that is actually really expensive process. Instead you should have a static instance of formatter for each date format

这篇关于TableView的数据不完整的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆