Разбиение на страницы PFQueryTableViewController не работает с heightForRowAtIndexPath

Я использую инфраструктуру parse.com со Swift и в PFQueryTableViewController, когда я устанавливаю нумерацию страниц, она не будет работать. Если в базе данных меньше строк, чем указано в objectPerPage, она работает нормально, но если строк больше, и когда я запускаю приложение, оно продолжает показывать экран загрузки, и ничего не загружается, когда я делаю "Провести как обновление", он вылетает как ошибка

*** 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)
}

}

2 ответа

Решение

Эта проблема возникает из-за PFQueryTableViewControllerРеализация метода tableView:numberOfRowsInSection от UITableViewDataSource, Я скопировал / вставил его из репозитория GitHub, содержащегоPFQueryTableViewController.m

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

Он просто возвращает количество отображаемых объектов (что имеет смысл), но если нумерация страниц включена, то для этого требуется дополнительная ячейка, которая будет показана. Это означает, что вам нужно вручную создать другую ячейку с текстом "Загрузить больше данных" или что-то в этом роде, что приведет к обновлению.


Способ преодолеть это просто переопределением 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 Pagination работает отлично. Проблемы возникают, когда пользователь переопределяет некоторые функции, используемые самим Parse, без должного управления строкой "Load More ...", добавленной Parse. В моем случае мне нужно было переопределить tableView-canEditRowAtIndexPath, чтобы определить, может или нет текущий пользователь удалить строку в соответствии с ACL объекта. Мой начальный функционал был:

переопределить 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 за пределами границ, когда строка Load More была встречена во время прокрутки списка. Проблема была решена добавлением этого теста:

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

Без этого кода Parse не добавляет строку "Загрузить еще..."! Итак, полный правильный переопределяющий функционал:

переопределить 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, когда включена разбивка на страницы.

НТН

Роберто Тарга

Другие вопросы по тегам