Ios Swift中的核心数据:比较for循环中的对象

Ios Swift中的核心数据:比较for循环中的对象,ios,swift,for-loop,core-data,Ios,Swift,For Loop,Core Data,我试图通过检查MPMediaItemPropertyPlayCount自上次检查以来是否有任何更改来更新用户的音乐播放历史记录。现在,每次检查时,我都会查询整个iPod库,并比较核心数据中已有的播放次数。如果当前播放计数!=播放计数存储在核心数据中,我们对这首歌做了一些处理,因为我们知道用户最近听过这首歌 在我的代码中,我正在努力循环浏览所有iPod歌曲,同时搜索相应的核心数据对象。下面的代码打印的行太多了。如何在for循环中搜索核心数据中的对象 class func checkiPodSong

我试图通过检查MPMediaItemPropertyPlayCount自上次检查以来是否有任何更改来更新用户的音乐播放历史记录。现在,每次检查时,我都会查询整个iPod库,并比较核心数据中已有的播放次数。如果当前播放计数!=播放计数存储在核心数据中,我们对这首歌做了一些处理,因为我们知道用户最近听过这首歌

在我的代码中,我正在努力循环浏览所有iPod歌曲,同时搜索相应的核心数据对象。下面的代码打印的行太多了。如何在
for
循环中搜索核心数据中的对象

class func checkiPodSongsForUpdate() {

        var appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        var context: NSManagedObjectContext = appDel.managedObjectContext!

        var newSong = NSEntityDescription.insertNewObjectForEntityForName("IPodSongs", inManagedObjectContext: context) as! NSManagedObject

        var request = NSFetchRequest(entityName: "IPodSongs")

        request.returnsObjectsAsFaults = false

        var results = context.executeFetchRequest(request, error: nil)


        let query = MPMediaQuery.songsQuery()

        let queryResult = query.collections as! [MPMediaItemCollection]

        for song in queryResult {

            for song in song.items as! [MPMediaItem] {

                request.predicate = NSPredicate(format: "title = %@", "\(song.valueForProperty(MPMediaItemPropertyTitle))")

                for result: AnyObject in results! {

                    if let playCount = result.valueForKey("playCount") as? String {

                        if playCount != "\(song.valueForProperty(MPMediaItemPropertyPlayCount))" {

                            println("\(song.valueForProperty(MPMediaItemPropertyTitle)) has a new play count.")

                        } else {

                            println("User hasn't listened to this song since last check.")
                        }
                    }
                }
            }
        }
    }

直接的问题是您为
request.predicate
赋值,但这样做没有效果。获取请求谓词只有在执行获取之前分配它时才有效。它成为获取的一部分,获取结果只包含与谓词匹配的对象

解决此特定问题有两种可能性:

  • 在循环内分配谓词后,在循环中提取核心数据。这将得到您期望的结果。然而,它也将是极其低效的,并且不能很好地扩展。获取请求是相对昂贵的操作,因此您可能会发现您花费了大量时间来执行它们

  • 不要将值赋给
    request.predicate
    ,而是通过执行以下操作过滤内存中的
    结果
    数组

    let predicate = NSPredicate(format: "title = %@", "\(song.valueForProperty(MPMediaItemPropertyTitle))")
    let currentResults = results.filteredArrayUsingPredicate(predicate)
    
    这将得到一个只包含与谓词匹配的歌曲的数组。这将比选项1更快,但仍然存在一个主要问题,即您在此处获取所有歌曲。这可能意味着每次调用此函数时都会将大量托管对象加载到内存中(假设用户有50000首歌曲?)。这仍然不是一个好的解决方案。不幸的是,我对
    MPMediaQuery
    了解不够,无法推荐更好的方法


  • 这两种方法都可以解决眼前的问题,但您需要解决更重要的概念问题。您正在比较两个潜在的大型集合,以查找单个匹配项。这将需要大量的CPU时间或内存,或者两者兼而有之,不管你如何处理。

    找到了我自己的解决方案。正如@Tom所说,如果每个数组中有足够的对象,在两个数组中循环可能会很昂贵。我决定在
    arrayOne
    中循环,并在该循环中调用一个自定义函数,该函数在
    arrayTwo
    中查找给定的键/值对

    // Custom function that returns Bool if arrayTwo contains a given key/value pair from inside the arrayOne loop
    
            func arrayContains(array:[[String:String]], #key: String, #value: String) -> Bool {
                for song in array {
                    if song[key] == value {
                        return true
                    }
                }
                return false
            }
    

    非常感谢@vacawama在此提供的帮助:

    谢谢你的回答,汤姆。但是我不能使用类型为
    NSPredicate
    的参数列表调用
    filteradarayusingpredicate
    。您更广泛的想法是将核心数据搜索结果存储在一个字典中(我将为每首歌曲提供标题、艺术家和播放计数),然后使用
    MPMediaQuery
    循环该字典?我不知道不能使用
    NSPredicate
    参数调用
    filteradarayusingpredicate
    是什么意思。这是调用该方法的唯一方法。不,我没有提到像你描述的那样使用字典,我也不推荐。我确实建议您尝试找到一个比您尝试比较两个大型对象集合更好的解决方案。我正在删除
    request.predicate
    行,并将其替换为您的建议,我得到了错误。这在Xcode中真的适用吗?这对我来说当然是有道理的,只是我不明白为什么我会犯这样的错误。