ios - 快速 - UITableview 在滚动时变得不稳定

标签 ios swift uitableview scroll

Am make a tableview listing, data loading dynamically and a image contain in cell and some text. When it scroll gets jerking and irritating the users

有任何提高表格 View 性能的想法吗?

class MainViewController: UIViewController,UITableViewDataSource, UITableViewDelegate {
    @IBOutlet weak var listTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.listTable.delegate = self
        self.listTable.dataSource = self
        self.listTable.separatorStyle = .None
        self.listTable.registerNib(UINib(nibName: "cellOne", bundle: nil), forCellReuseIdentifier: "cellOne")
        self.listTable.registerNib(UINib(nibName: "cellTwo", bundle: nil), forCellReuseIdentifier: "cellTwo")
        self.listTable.registerNib(UINib(nibName: "cellThree", bundle: nil), forCellReuseIdentifier: "cellThree")
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int{
        return 1
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if pageIndex == 7 {
            return 120
        } else if indexPath.row == 0  {
            return 280
        } else if (indexPath.row == 5 || indexPath.row == 4) {
            return 200
        } else if (indexPath.row == 8 || indexPath.row == 11) {
            return 160
        }
        return 80
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return 50
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        let listArray = self.listDataArray[indexPath.row]

        if indexPath.row == 0 && pageIndex != 7 {
            var cell = tableView.dequeueReusabl eCellWithIdentifier("cellOne") as! cellOne!

            if cell == nil {
                tableView.registerClass(cellOne.classForCoder(), forCellReuseIdentifier: "cellOne")
                cell = cellOne(style: UITableViewCellStyle.Default, reuseIdentifier: "cellOne")
            }

            cell.headLbl.text = "\(listArray["title"]!)".html2String
            cell.addImageView.userInteractionEnabled = true
            let guster = UITapGestureRecognizer(target: self, action: "addTarget:")
            cell.addImageView.addGestureRecognizer(guster)
            cell.addImageView.tag = 1

            let qualityOfServiceClass = QOS_CLASS_BACKGROUND
            let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
            dispatch_async(backgroundQueue, {
                if listArray["image"] != nil && self.imagesLocalDictionary[indexPath.row] == nil {
                    let u = listArray["image"] as! String
                    let url = NSURL(string: u)
                    if url != nil {
                        let data = NSData(contentsOfURL: url!)

                        if data != nil {
                            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                                cell.imageViews.image = UIImage(data: data!)
                            })
                            self.imagesLocalDictionary.setObject(data!, forKey: indexPath.row)
                        }
                    }
                } else {
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        cell.imageViews.image = UIImage(data: self.imagesLocalDictionary[indexPath.row] as! NSData)

                    })
                }
            })


            if Constants.sharedInstance.addData["1"] != nil {
                cell.addImageView.image = UIImage(data: Constants.sharedInstance.addData["1"] as! NSData)
            }

            return cell

        } else if indexPath.row == 4 && pageIndex != 7 {
            var cell = tableView.dequeueReusableCellWithIdentifier("cellTwo") as! cellTwo!

            if cell == nil {
                tableView.registerClass(cellTwo.classForCoder(), forCellReuseIdentifier: "cellTwo")
                cell = cellTwo(style: UITableViewCellStyle.Default, reuseIdentifier: "cellTwo")
            }

            cell.headLbl.text = "\(listArray["title"]!)".html2String
            cell.addImageView.userInteractionEnabled = true
            let guster = UITapGestureRecognizer(target: self, action: "addTarget:")
            cell.addImageView.addGestureRecognizer(guster)
            cell.addImageView.tag = 2

            let qualityOfServiceClass = QOS_CLASS_BACKGROUND
            let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
            dispatch_async(backgroundQueue, {
                if listArray["image"] != nil && self.imagesLocalDictionary[indexPath.row] == nil {
                    let u = listArray["image"] as! String
                    let url = NSURL(string: u)
                    if url != nil {
                        let data = NSData(contentsOfURL: url!)

                        if data != nil {
                            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                                cell.imageViews.image = UIImage(data: data!)
                            })
                            self.imagesLocalDictionary.setObject(data!, forKey: indexPath.row)
                        }

                    }
                } else {
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        cell.imageViews.image = UIImage(data: self.imagesLocalDictionary[indexPath.row] as! NSData)
                    })
                }
            })

            if Constants.sharedInstance.addData["2"] != nil {
                cell.addImageView.image = UIImage(data: Constants.sharedInstance.addData["2"] as! NSData)
            }

            return cell

        } else if indexPath.row == 5 && pageIndex != 7 {
            var cell = tableView.dequeueReusableCellWithIdentifier("cellThree") as! cellThree!

            if cell == nil {
                tableView.registerClass(cellThree.classForCoder(), forCellReuseIdentifier: "cellThree")
                cell = cellThree(style: UITableViewCellStyle.Default, reuseIdentifier: "cellThree")
            }

            cell.headLbl.text = "\(listArray["title"]!)".html2String
            cell.addImageView.userInteractionEnabled = true
            let guster = UITapGestureRecognizer(target: self, action: "addTarget:")
            cell.addImageView.addGestureRecognizer(guster)
            cell.addImageView.tag = 3

            let qualityOfServiceClass = QOS_CLASS_BACKGROUND
            let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

            dispatch_async(backgroundQueue, {
                if listArray["image"] != nil && self.imagesLocalDictionary[indexPath.row] == nil {
                    let u = listArray["image"] as! String
                    let url = NSURL(string: u)
                    if url != nil {
                        let data = NSData(contentsOfURL: url!)

                        if data != nil {
                            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                                cell.imageViews.image = UIImage(data: data!)
                            })
                            self.imagesLocalDictionary.setObject(data!, forKey: indexPath.row)
                        }
                    }
                } else {
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        cell.imageViews.image = UIImage(data: self.imagesLocalDictionary[indexPath.row] as! NSData)
                    })
                }
            })

            if Constants.sharedInstance.addData["3"] != nil {
                cell.addImageView.image = UIImage(data: Constants.sharedInstance.addData["3"] as! NSData)
            }

            return cell
        } else {
            cell.backgroundColor = UIColor.groupTableViewBackgroundColor()

            let container = UIView()
            container.frame = CGRectMake(2, 1, tableView.frame.width-4, 78)
            container.backgroundColor = UIColor.whiteColor()
            cell.addSubview(container)

            let headerLbl = UILabel()
            headerLbl.backgroundColor = UIColor.clearColor()

            headerLbl.frame = CGRectMake(120, 1, self.view.frame.width-130, 76)
            headerLbl.numberOfLines = 0
            headerLbl.font = UIFont(name: "TelegramHead", size: 18)

            headerLbl.text = "\(listArray["title"]!)".html2String
            headerLbl.lineBreakMode = NSLineBreakMode.ByCharWrapping

            let imageView = UIImageView()
            imageView.frame = CGRectMake(5, 5, 100, 68)
            imageView.image = UIImage(named: "place_holder.jpg")
            imageView.contentMode = UIViewContentMode.ScaleAspectFill
            imageView.clipsToBounds = true

            let blackLayerView = UIView();
            blackLayerView.frame = CGRectMake(0, 0, 0, 0);
            blackLayerView.backgroundColor = UIColor.blackColor();
            blackLayerView.alpha = 0.4;

            container.addSubview(imageView)
            container.addSubview(blackLayerView);
            container.addSubview(headerLbl)

            if pageIndex == 7 {
                container.frame = CGRectMake(2, 1, tableView.frame.width-4, 118)
                imageView.frame = CGRectMake(5, 5, container.frame.width-10, 108)
                blackLayerView.frame = imageView.frame;
                headerLbl.frame = imageView.frame//CGRectMake(10, 5, self.view.frame.width-20, 100)
                headerLbl.textColor = UIColor.whiteColor()
                headerLbl.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.2)

            } else if (indexPath.row == 8 || indexPath.row == 11) && pageIndex != 7 {
                let add = UIImageView()
                add.frame = CGRectMake(2, 82, tableView.frame.width-4, 76)
                //add.contentMode = UIViewContentMode.ScaleAspectFit;
                cell.addSubview(add)
                add.userInteractionEnabled = true
                let guster = UITapGestureRecognizer(target: self, action: "addTarget:")
                add.addGestureRecognizer(guster)

                if Constants.sharedInstance.addData["4"] != nil && indexPath.row == 8{
                    add.image = UIImage(data: Constants.sharedInstance.addData["4"] as! NSData)
                    add.tag = 4
                }

                if Constants.sharedInstance.addData["5"] != nil && indexPath.row == 11{
                    add.image = UIImage(data: Constants.sharedInstance.addData["5"] as! NSData)
                    add.tag = 5
                }
            }

            let qualityOfServiceClass = QOS_CLASS_BACKGROUND
            let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

            dispatch_async(backgroundQueue, {
                if listArray["image"] != nil && self.imagesLocalDictionary[indexPath.row] == nil {
                    let u = listArray["image"] as! String
                    let url = NSURL(string: u)
                    if url != nil {
                        let data = NSData(contentsOfURL: url!)


                        if data != nil {
                            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                                imageView.image = UIImage(data: data!)
                                self.imagesLocalDictionary.setObject(data!, forKey: indexPath.row)
                            })
                        }
                    }

                } else {
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        imageView.image = UIImage(data: self.imagesLocalDictionary[indexPath.row] as! NSData)
                    })
                }
            })
        }
        return cell
    }
}

我确实获得了所需的功能。但是 TableView 上有一个非常不自然的抖动,这会导致糟糕的用户体验。

最佳答案

您可以对此代码进行许多改进以提高性能。

  1. 不要在 cellForRow 中注册单元格
  2. 为每个单元格定义特定的自定义类并注册它们以便在 viewDidLoad 中重用
  3. 减少 cellForRowAt 中使用的逻辑
  4. 在 cellForRowAt 的开头,您创建一个单元格的新实例,然后如果没有其他情况匹配,则向其中添加 subview 。该单元无法重复使用。始终重复使用。您将使用更少的资源

我之前已经构建了一个复杂的 TableView ,并创建了为特定索引路径配置和返回可重用单元格的函数。

class LargeImageCell: UITableViewCell {
   var imageView: UIImageView()

   // in init, init the cell, add imageview as subview, setup constraints

   func setContent(imageURL: URL) {
      // load image from cache or fetch from network in background
   }
}

// in tableview/view controller
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
   switch indexPath.row {
     case 0:
        return self.getLargeImageCell(indexPath: indexPath)
     // all other cases
   }
}

这大致就是我的实现方式,只是尝试减少单元格中的逻辑量,我总是发现最好创建自定义单元格,而不是将它们添加到 cellForRowAt 中,让单元格自行配置

func getLargeImageCell(indexPath: NSIndexPath) -> UITableViewCell {
    let data = self.data[indexPath.row] // model from db

    var cell: UITableViewCell
    if let c = self.tableView.dequeueReusableCellWithIdentifier("largeImageCell") as? LargeImageCell {
       cell = c
    } else {
       cell = LargeImageCell(style: UITableViewCellStyle.Default, reuseIdentifier: "largeImageCell")
    }
    cell.setContent(imageURL: data.imageURL)
    return cell
} 

关于ios - 快速 - UITableview 在滚动时变得不稳定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43365848/

相关文章:

javascript - 从javascript/html播放音频时设置自定义元数据(Control Center iOS)

arrays - Swift 选择器 caseInsensitiveCompare

ios - 永远不会调用 TableView cellForRowAtIndexPath(iOS、Swift)

swift - 将 TableViewController 设置为 Root View Controller

后台模式下的IOS应用

IOS/swift :syntax to return custom object in closure

cocoa-touch - 运行时 xib 下载?

ios - 使用 Swift 与需要 block 作为参数的 Objective C 方法进行交互

ios - swift 3.0 的 map View 注释委托(delegate)

ios - 允许在 TableView 行选择时执行条件操作