在 cellForRowAtIndexPath 中使用 PFQuery

Posted

技术标签:

【中文标题】在 cellForRowAtIndexPath 中使用 PFQuery【英文标题】:Using PFQuery inside cellForRowAtIndexPath 【发布时间】:2015-12-08 14:19:50 【问题描述】:

我在想PFQuery

我正在开发一个向用户显示 Feed 的应用,它还为每个帖子显示一个 Like 计数器(如 Facebook 应用或 Instagram 应用)。

所以在我的PFQueryTableViewController 我有我的主要查询,基本上显示所有帖子:

override func queryForTable() -> PFQuery 
    let query = PFQuery(className: "Noticias")
    query.orderByDescending("createdAt")   
    return query

我使用另一个查询来计算 Parse 中包含所有喜欢的另一个类的点赞数。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? 
    var cell = tableView.dequeueReusableCellWithIdentifier("FeedCellIdentifier") as! FeedCell!
    if cell == nil 
        cell = FeedCell(style: UITableViewCellStyle.Default, reuseIdentifier: "FeedCellIdentifier")
    

    let query2 = PFQuery(className:"commentsTable")
    query2.whereKey("newsColumn", equalTo: object!)
    query2.findObjectsInBackgroundWithBlock 
        (objectus: [PFObject]?, error: NSError?) -> Void in

        if error == nil 

            let quantidade = objectus!.count

            let commentQuantidade = String(quantidade)

            cell.comentariosLabel.text = commentQuantidade
         else 
            // Log details of the failure
            print("Error: \(error!) \(error!.userInfo)")
        
    

这种编码方式有效,我实现了我想要的,但是!我知道我正在重用单元格,我知道每次出现单元格时都会调用这段代码。

我知道这些事实:

    每次滚动表格视图时都会向 Parse Cloud 发送大量查询请求

    1234563这可行,但不利于用户体验。

所以,我的主要疑问是,这是正确的编码方式吗?我不这么认为,我只是想要另一种观点或想法。

谢谢。

编辑 1

正如我所说,我已将计数方法更新为 countObjectsInBackgroundWithBlock 而不是 findObjectsInBackgroundWithBlock,但我无法将查询移动到 ViewDidLoad,因为我使用 object 来检查每个有多少 cmets帖子有。

编辑 2 我已经嵌入查询来计算每个帖子的 cmets 数量并打印结果,现在我认为我的代码比以前的版本更好,但我无法将结果传递给标签,因为我'我收到一个错误:

使用未解析的标识符“commentCount”

我正在阅读一些关于 Struct 的文档

按照我更新的代码如下:

import UIKit
import Social

class Functions: PFQueryTableViewController, UISearchBarDelegate 

override func shouldAutorotate() -> Bool 
    return false


var passaValor = Int()
let swiftColor = UIColor(red: 13, green: 153, blue: 252)
struct PostObject
    let post : PFObject
    let commentCount : Int


var posts : [PostObject] = []


// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) 
    super.init(style: style, className: className)


required init(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)!
    // The className to query on
    self.parseClassName = "Noticias"

    // The key of the PFObject to display in the label of the default cell style
    self.textKey = "text"

    // Uncomment the following line to specify the key of a PFFile on the PFObject to display in the imageView of the default cell style
    self.imageKey = "image"

    // Whether the built-in pull-to-refresh is enabled
    self.pullToRefreshEnabled = true

    // Whether the built-in pagination is enabled
    self.paginationEnabled = true

    // The number of objects to show per page
    self.objectsPerPage = 25


// Define the query that will provide the data for the table view

override func queryForTable() -> PFQuery 
    let query = super.queryForTable()

    return query




override func viewWillAppear(animated: Bool) 
    super.viewWillAppear(true)
    loadObjects()


// In a storyboard-based application, you will often want to do a little preparation before navigation
override func viewDidLoad() 
    super.viewDidLoad()
    // navigationBarItems()


    let query = PFQuery(className:"Noticias")
    query.findObjectsInBackgroundWithBlock 
        (objects: [PFObject]?, error: NSError?) -> Void in

        // The find succeeded.
        print("Successfully retrieved \(objects!.count) scores.")
        // Do something with the found objects
        if let objects = objects 
            for object in objects 
                let queryCount = PFQuery(className:"commentsTable")
                queryCount.whereKey("newsColumn", equalTo: object)
                queryCount.countObjectsInBackgroundWithBlock 
                    (contagem: Int32, error: NSError?) -> Void in
                    let post = PostObject(object, commentCount:commentCount)
                    posts.append(post)
                    print("Post \(object.objectId!) has \(contagem) comments")
                
                self.tableView.reloadData()
            
        
    

    //Self Sizing Cells
    tableView.estimatedRowHeight = 350.0
    tableView.rowHeight = UITableViewAutomaticDimension






// Define the query that will provide the data for the table view

//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? 
var cell = tableView.dequeueReusableCellWithIdentifier("FeedCellIdentifier") as! FeedCell!
if cell == nil 
    cell = FeedCell(style: UITableViewCellStyle.Default, reuseIdentifier: "FeedCellIdentifier")


cell?.parseObject = object

if let assuntoNoticia = object?["assunto"] as? String 
    cell?.assuntoNoticia?.text = assuntoNoticia



if let pontos = object?["pontos"] as? Int 
    let pontosPosts = String(pontos)
    cell?.pontosLabel?.text = String(pontosPosts)



if let zonaLabel = object?["zona"] as? String 
    cell?.zonaLabel?.text = zonaLabel



if let criticidade = object?["criticidade"] as? String 
    if criticidade == "Problema"

        cell.criticidadeNoticia.backgroundColor = UIColor.redColor()
     else 
        cell.criticidadeNoticia.backgroundColor = UIColor.greenColor()
    


return cell


以及打印的结果:

成功检索到 5 个分数。

发布 wSCsTv8OnH 有 4 个 cmets

发布 LbwBfjWPod 有 0 个 cmets

发布 fN4ISVwqpz 有 0 个 cmets

发布 1rXdQr2A1F 有 1 cmets

发布 eXogPeTfNu 有 0 个 cmets

【问题讨论】:

【参考方案1】:

更好的做法是在视图加载时查询所有数据并将其保存到模型中,然后在表视图滚动时从中读取数据。处理查询时,您可以显示下载指示符或占位符数据。查询完成后,您将致电tableView.reloadData()

您可以通过像这样创建一个新变量来完成此操作:

 var cellModels : [PFObject] = []

在你的query2.findObjectsInBackgroundWithBlock:

 for object in objectus
   self.cellModels.append(object)
 
 self.tableView.reloadData()

cellForRowAtIndexPath:

let model = cellModels[indexPath.row]
// configure cell according to model
// something like cell.textLabel.text = model.text

P.S 如果您只需要获取对象的数量,您应该查看方法 countObjectsInBackgroundWithBlock。因为如果有很多例如 cmets findObjectsInBackgroundWithBlock 将返回最多 1000 个对象,但您仍然不会下载整个对象,只有一个数字这将加快查询速度并节省用户的蜂窝计划。

更新:另外,如果您需要存储 cmets 的数量,您可以像这样创建简单的 struct

struct PostObject
 let post : PFObject
 let commentCount : Int


var posts : [PostObject] = []

当您查询您的帖子时,您会遍历收到的对象并填充 posts 数组。

for object in objects
  // create countObjectsInBackgroundWithBlock query to get comments count for object
  // and in result block create
  let post = PostObject(object, commentCount:commentCount)
  posts.append(post)

 
tableView.reloadData()

cellForRowAtIndexPath:

let post = posts[indexPath.row]
cell.postCountLabel.text = String(post.commentCount)
// configure cell accordingly

【讨论】:

很好的答案,我正在尝试在我的代码中应用您所解释的内容,我会发布更新。 我已阅读文档并将我的方法改进为 countObjectsInBackgroundWithBlock 而不是 findObjectsInBackgroundWithBlock ,现在当我将查询移动到 viewDidLoad 时,我无法引用对象 query2.whereKey("newsColumn", equalTo: object!) object 是什么类型的?你在哪里分配它? 是的,它看起来比一开始好多了。您应该将(contagem: Int32, error: NSError?) -> Void in let post = PostObject(object, commentCount:commentCount) 替换为(contagem: Int32, error: NSError?) -> Void in let post = PostObject(object, commentCount: contagem) 请报告您的进度,我来帮忙了。 你的numberOfRowsInSection方法是什么?我会把return posts.count 放在那里。【参考方案2】:

您应该在表格视图中显示信息之前进行查询。

【讨论】:

以上是关于在 cellForRowAtIndexPath 中使用 PFQuery的主要内容,如果未能解决你的问题,请参考以下文章

在 cellForRowAtIndexPath 中获取 iOS CoreData 后台线程

UIView 在 cellForRowAtIndexPath 中重叠/再次创建

无法在 cellForRowAtIndexPath 中获取单元格框架或约束

为啥图像未显示在目标 C 的 cellforRowAtIndexPath 中

nib 项目中的 CellForRowAtIndexPath

我应该在 tableView(_:cellForRowAtIndexPath:) 方法中为自定义单元格写啥?