'阵列≤(对象)>'不能转换为Bool'

时间:2015-02-24 09:49:33

标签: ios arrays swift core-data filter

假设有一个名为Post的课程(如在论坛帖子中)。

class Post: NSManagedObject {

    @NSManaged var id: NSNumber
    @NSManaged var title: String?
    @NSManaged var body: String?
    @NSManaged var voteCount: NSNumber?
    @NSManaged var thread: Thread?
}

Thread课程。

class Thread: NSManagedObject {

    @NSManaged var topic: String
    @NSManaged var id: NSNumber
    @NSManaged var posts: NSSet
}

一个线程包含一组Post个对象。

从本地核心数据库中,我将Thread个对象的数组检索到var threads = [Thread]()

enter image description here

现在我需要过滤掉投票数超过0的线程中的帖子。换句话说,我需要一个Thread个对象数组,不包括Post个0票。

这是我到目前为止所尝试的内容。

var filteredThreads = threads.filter() { $0.posts.filter() { $0.voteCount > 0 } }

但我收到错误'数组<(Post)>'不能转换为'Bool'

似乎我不能使用这样的嵌套过滤器。或者我做错了吗?


编辑:我还尝试了以下代码。没有编译时错误,但它没有按预期过滤返回的结果数组。

threads = items.filter() {
    for post in $0.posts.allObjects as [Post] {
        if post.voteCount!.integerValue > 0 {
            return true
        }
    }
    return false
}

我上传了一个Xcode项目here来证明这个问题。任何帮助表示赞赏。

感谢。


尝试2:我尝试迭代我收到的Thread个对象并过滤掉其中的Post个内容。但我不知道如何将过滤后的数组添加回Thread对象。

if let items = viewModel.getThreads() {
    for thread in items {
        let posts = thread.posts.allObjects as [Post]
        var s = posts.filter() {
            if $0.voteCount!.integerValue > 0 {
                return true
            } else {
                return false
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

你的方法无法运作。你不能过滤这样的Thread对象 你得到一个"修改过的"线程对象只是 与积极投票计数相关的帖子。过滤总是给出一个 原始对象的子集,但不修改这些对象。

实现所需内容的正确方法是获取所有Post对象 积极投票计数,并根据他们分组 他们的主题。

最简单的方法是NSFetchedResultsController

这是一个快速而又脏的版本的ForumViewController 使用获取的结果控制器。其中大部分是样板代码 您可以使用标准的" Master-Detail Application + Core Data" 在Xcode中。它当然可以改进,但希望能得到你 在正确的轨道上。

要在示例项目中进行此编译,managedObjectContextForumViewModel中需要成为公共财产。 或者,您可以移动提取的结果控制器创建 进入ForumViewModel班。

// ForumViewController.swift:
import UIKit
import CoreData

class ForumViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    private let viewModel = ForumViewModel()

    var fetchedResultsController: NSFetchedResultsController {
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
        }

        // Fetch "Post" objects:
        let fetchRequest = NSFetchRequest(entityName: "Post")

        // But only those with positive voteCount:
        let predicate = NSPredicate(format: "voteCount > 0")
        fetchRequest.predicate = predicate

        // First sort descriptor must be the section key:
        let topicSort = NSSortDescriptor(key: "thread.topic", ascending: true)
        // Second sort descriptor to sort the posts in each section:
        let titleSort = NSSortDescriptor(key: "title", ascending: true)
        fetchRequest.sortDescriptors = [topicSort, titleSort]

        // Fetched results controller with sectioning according the thread.topic:
        let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
                managedObjectContext: viewModel.managedObjectContext,
                sectionNameKeyPath: "thread.topic", cacheName: nil)
        aFetchedResultsController.delegate = self
        _fetchedResultsController = aFetchedResultsController

        var error: NSError? = nil
        if !_fetchedResultsController!.performFetch(&error) {
            abort()
        }
        return _fetchedResultsController!
    }
    var _fetchedResultsController: NSFetchedResultsController? = nil

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.fetchedResultsController.sections?.count ?? 0
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
        return sectionInfo.numberOfObjects
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        self.configureCell(cell, atIndexPath: indexPath)
        return cell
    }

    func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
        let post = self.fetchedResultsController.objectAtIndexPath(indexPath) as Post
        cell.textLabel!.text = post.title
        cell.detailTextLabel!.text = "\(post.voteCount!)"
    }

    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
        return sectionInfo.name
    }

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        self.tableView.beginUpdates()
    }

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
        switch type {
        case .Insert:
            self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        case .Delete:
            self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        default:
            return
        }
    }

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch type {
        case .Insert:
            tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
        case .Delete:
            tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
        case .Update:
            self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!)
        case .Move:
            tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
            tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
        default:
            return
        }
    }

    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        self.tableView.endUpdates()
    }
}

结果:

enter image description here

答案 1 :(得分:1)

$0.posts.filter() { $0.voteCount > 0 }会返回Post数组,voteCount为正数。你必须检查它的count

var filteredThreads = threads.filter() {
    $0.posts.filter({ $0.voteCount > 0 }).count > 0
    //                                   ^^^^^^^^^^
}

但是,这无条件地迭代所有posts。相反,您应该尽快return true

var filteredThreads = threads.filter() {
    for p in $0.posts {
        if p.voteCount > 0 {
            return true
        }
    }
    return false
}

答案 2 :(得分:0)

过滤器内的函数必须返回类型为' Bool'

的内容

我认为以下代码可能对您有用

var filteredThreads = threads.filter({
   var result = false;
   for (var i = 0; i<$0.posts.count;i++) {
      if ($0.posts[i].voteCount > 0){
           result = true;
      }
   }
   return result
})

This博文可能会变得有用