ios - 如何提高 UITableView 的性能
问题描述
我有一个UITableView
从 firebase 数据库加载图像。表格中的每个单元格包含三张图片。firestore 查询一次加载三个文档,而表格视图在用户滚动到底部时分页。我遇到的问题是,当我滚动表格视图时,每次到达新单元格时都会出现口吃。每个单元格占用的空间比全屏多一点。这是我试图描述的一个例子:https ://imgur.com/a/xRB6gZg
这是产生这些问题的代码:
func paginate(){
postQuery = postQuery.start(afterDocument: documents.last!)
self.loadPosts()
}
//queries Firestore and loads into postArray
func loadPosts() {
if let blockedArray = userDefaults.array(forKey: blockKey) as? [String]{
blockedUsers = blockedArray
}
postQuery.getDocuments{ [weak self](querySnapshot, error) in
self!.q.async{
if let err = error {
print(err)
}else{
var postsTemp = self?.postArray
for doc in querySnapshot!.documents{
self?.documents += [doc]
let post = self!.createPost(doc)
if(!self!.postArray.contains(post) && !self!.blockedUsers.contains(post.uid)){
postsTemp?.append(post)
}
DispatchQueue.main.async {
self!.postArray = postsTemp!
self!.tableView.reloadData()
self!.isNewDataLoading = false
}
}
self!.loadedFirst = true
}
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if postArray.count == 0{
return 1
}else{
return postArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var post: PostStruct
var peopleUserIsFollowing: [String] = []
let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! PostCell
cell.delegate = self
if postArray.count == 0 {
let instructions = cell.textLabel
instructions?.text = "Press the camera to start Piking!"
instructions?.textAlignment = .center
clearPosts(cell)
}else {
post = postArray[indexPath.row]
if let leftPostArray = userDefaults.array(forKey: fbLeftKey) as? [String]{
votedLeftPosts = leftPostArray
}
if let rightPostArray = userDefaults.array(forKey: fbRightKey) as? [String]{
votedRightPosts = rightPostArray
}
let firstReference = storageRef.child(post.firstImageUrl)
let secondReference = storageRef.child(post.secondImageUrl)
//For FriendsTableView query
let db = Firestore.firestore()
let followingReference = db.collection("following")
.document(currentUser!)
.collection("UserIsFollowing")
followingReference.getDocuments(){(querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
peopleUserIsFollowing.append(document.documentID)
}
}
}
//Fill in labels and imageViews
cell.timer = createTimer(post, cell)
cell.firstImageView.sd_setImage(with: firstReference)
cell.secondImageView.sd_setImage(with: secondReference)
cell.leftTitle.text = post.firstTitle
cell.rightTitle.text = post.secondTitle
cell.postDescription.text = post.postDescription + "\(indexPath)"
if post.userPic == "" {
userPic =
"https://firebasestorage.googleapis.com/v0/b/pikit-7e40e4.appspot.com/o/Default%20Profile%20Pic.png?alt=media&token=2bc88382-2ad3-4eb8-8163-dcddf391c666"
} else{
userPic = post.userPic
}
let url = URL(string: userPic)
let data = try? Data(contentsOf: url!)
cell.profilePic.image = UIImage(data: data!)
let votesCollection = db.collection("votes").document(post.postID)
getCount(ref: votesCollection, cell: cell)
if(post.uid != currentUser){
cell.userName.text = post.poster
}else{
cell.userName.text = "Me"
cell.tapLeft.isEnabled = false
cell.tapRight.isEnabled = false
}
cell.textLabel?.text = ""
if(post.poster == Auth.auth().currentUser!.uid || post.endDate - Int(NSDate().timeIntervalSince1970) <= 0){
cell.tapRight.isEnabled = false
cell.tapLeft.isEnabled = false
cell.firstImageView.layer.borderWidth = 0
cell.secondImageView.layer.borderWidth = 0
}
else if(votedRightPosts.contains(post.firstImageUrl)){
cell.secondImageView.layer.borderColor = UIColor.green.cgColor
cell.secondImageView.layer.borderWidth = 4
cell.firstImageView.layer.borderWidth = 0
cell.tapRight.isEnabled = false
cell.tapLeft.isEnabled = true
}
else if (votedLeftPosts.contains(post.firstImageUrl)){
cell.firstImageView.layer.borderColor = UIColor.green.cgColor
cell.firstImageView.layer.borderWidth = 4
cell.secondImageView.layer.borderWidth = 0
cell.tapLeft.isEnabled = false
cell.tapRight.isEnabled = true
}
}
return cell
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let postCell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! PostCell
clearPosts(postCell)
postCell.timer?.invalidate()
postCell.timer = nil
}
override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
//Bottom Refresh
if scrollView == tableView{
if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height)
{
if !isNewDataLoading{
isNewDataLoading = true
paginate()
}
}
}
}
我试过调整什么didEndDisplaying
,比如清除细胞/不清除细胞,但这没有效果。我也尝试过改变调用 paginate 的位置,但这似乎是最好的方法。我不确定我哪里出错了。我还在 Xcode 调试器中注意到,随着表格视图的上下滚动,应用程序的内存使用量稳步上升,但似乎从未下降。
解决方案
通常,您有两种选择来解决此问题。要解析的代码很多,所以我不能给你一个代码示例,但答案是:
预取
当您滚动到第 2 项时,请在向下滚动之前开始获取第 4、5、6 项(因为您一次获取 3 个)。
另外...您可能会考虑一次获取超过 3 个。比如... 50 或 100。现代 iOS 设备有很多内存。我想不出将其限制在这么少的真正理由。
占位符
构建您的布局,以便它提供占位符数据,然后异步启动获取以使用真实数据更新屏幕布局。
无论哪种方式都需要您稍微重构一下代码。我的直觉说,预取对你来说会更容易。
推荐阅读
- python - Xarray沿相同维度添加(如求和)两行但坐标值不同
- django - 抽象用户 django 创建不同的表,但它没有显示在数据库中
- web - 其他网站的开发环境
- docker - ModuleNotFoundError:创建 Dockerfile 时没有名为“OpenSSL”的模块
- python - Pandas:New_Column = Column_A - Column_B,New_Column 中的值是 New_Column 的第一个单元格的值。需要修复
- python - Python Flask MySQL:如何持久存储连接池对象?
- android - 搜索视图不起作用
- python - curses.KEY_UP 和 curses.KEY_DOWN 在使用 npyscreen 时不起作用
- java - 使用 Cucumber 时,您将初始化任务(例如读取属性文件等)放在哪里
- laravel - 如何从 laravel 7 中的中间表(多对多)中获取特定数据?