PFQueryTableViewController 分页不适用于 heightForRowAtIndexPath

PFQueryTableViewController pagination doesn't work with heightForRowAtIndexPath

我将 parse.com 框架与 Swift 一起使用,当我在 PFQueryTableViewController 中设置分页时,它不起作用。如果数据库的行数少于 objectPerPage 中设置的数量,它工作正常,但如果有更多的行并且当我 运行 应用程序时它一直显示加载屏幕并且没有下载任何东西,当我 "swipe as refresh" 它崩溃了 错误

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 4]

ImagesTableViewController.swift

import UIKit
import Parse
import ParseUI
import Bolts

class ImagesTableViewController: PFQueryTableViewController {
@IBAction func unwindToSegue (segue : UIStoryboardSegue) {}

// 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)

    // Configure the PFQueryTableView
    self.parseClassName = "Image"
    self.pullToRefreshEnabled = true
    self.paginationEnabled = true
    self.objectsPerPage = 5

}

// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery {
    var query = PFQuery(className: "Image")
    query.whereKey("deleted", notEqualTo: 1)
    query.orderByDescending("createdAt")
    return query
}

//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {

    var cell = tableView.dequeueReusableCellWithIdentifier("ImageCell") as! ImageTVCell!
    if cell == nil {
        cell = ImageTVCell(style: UITableViewCellStyle.Default, reuseIdentifier: "ImageCell")
    }

    // Extract values from the PFObject to display in the table cell HEADLINE
    if let caption = object?["caption"] as? String {
        cell?.headlineLabel?.text = caption
    }

    // Display image
    var initialThumbnail = UIImage(named: "question")
    cell.postImageView.image = initialThumbnail
    if let thumbnail = object?["image"] as? PFFile {
        cell.postImageView.file = thumbnail
        cell.postImageView.loadInBackground()
    }

    return cell
}

// if I remove this code pagination work but the cell height is wrong
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return calculateHeightForRowAtIndexPath(indexPath)
}


func calculateHeightForRowAtIndexPath(indexPath: NSIndexPath) -> CGFloat {
    if let ratio = objectAtIndexPath(indexPath)?["aspect"] as? Float {
        println("Ratio: \(ratio)")
        return tableView.bounds.size.width / CGFloat(ratio)
    } else {
        return 50.0
    }
}


@IBAction func addNewPhotoButton(sender: UIBarButtonItem) {
    self.tabBarController?.tabBar.hidden = true
    self.performSegueWithIdentifier("showUploadNewImage", sender: self)
}

}

出现此问题是因为 PFQueryTableViewController 实施了 UITableViewDataSource 中的方法 tableView:numberOfRowsInSection。我从 GitHub repo containing PFQueryTableViewController.m

copy/pasted
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSInteger count = [self.objects count];
    if ([self _shouldShowPaginationCell]) {
        count += 1;
    }
    return count;
}

它只是 returns 要显示的对象的数量(这是有道理的),但是如果启用分页,则需要显示一个额外的单元格。这意味着您必须手动创建另一个包含文本 "Load more data" 或类似内容的单元格,这将触发刷新。


克服这个问题的一种方法是用以下内容覆盖 tableView:numberOfRowsInSection 自己:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.objects!.count
}

更新 1

预建 Parse 分页按钮在之前的答案中消失了


使用以下代码片段计算单元格的高度以显示预建的 Parse 分页按钮

func calculateHeightForRowAtIndexPath(indexPath: NSIndexPath) -> CGFloat {
    // Special case for pagination, using the pre-built one by Parse
    if (indexPath.row >= objects!.count) { return 50.0 }

    // Determines the height if an image ratio is present
    if let ratio = objectAtIndexPath(indexPath)?["aspect"] as? Float {
        println("Ratio: \(ratio)")
        return tableView.bounds.size.width / CGFloat(ratio)
    } else {
        return 50.0
    }
}

将 Parse 1.11 与 iOS 9.2 和 Xcode 7.2 Parse 分页结合使用可以完美运行。 当用户覆盖 Parse 本身使用的某些功能而没有正确管理 Parse 添加的 "Load More ..." 行时,问题就会浮出水面。 在我的例子中,我需要覆盖 tableView-canEditRowAtIndexPath 以确定当前用户是否可以或不能根据对象的 ACL 删除行。 我的初始功能是:

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {

    if let curUser = PFUser.currentUser() {
        let currentObject = objects![indexPath.row]
        if let acl = currentObject.ACL {
            return acl.getWriteAccessForUser(curUser)
        } else {
           return true
        }
    }
    return true
}

但在列表滚动期间遇到加载更多行时,我得到了 indexpath out of bounds 的异常。 添加此测试后问题已解决:

    if (indexPath.row == self.objects!.count) { // row "Load More ..."
        return true
    }

如果没有此代码,Parse 将不会添加 "Load More ..." 行!! 所以完整正确的覆盖函数是:

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {

    if (indexPath.row == self.objects!.count) { // row "Load More ..."
        return true
    }
    if let curUser = PFUser.currentUser() {
        let currentObject = objects![indexPath.row]
        if let acl = currentObject.ACL {
            return acl.getWriteAccessForUser(curUser)
        } else {
           return true
        }
    }
    return true
}

一般来说,包括 heightForRowAtIndexpath 在内的所有重写函数都必须处理启用分页时由 Parse 添加的额外行。

HTH

罗伯托·塔尔加