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

时间:2015-05-22 20:51:42

标签: ios swift for-loop core-data

我试图通过检查自上次检查后是否有任何MPMediaItemPropertyPlayCount更改来更新用户的音乐收听历史记录。现在,每次检查时,我都会查询整个iPod库并比较Core Data中现有的播放次数。如果当前播放计数!=存储在核心数据中的播放计数,我们会对该歌曲执行某些操作,因为我们知道用户最近已经听过它。

在我的代码中,我正在努力遍历所有iPod歌曲同时搜索相应的Core Data对象。下面的代码打印出的方式太多了线。如何在for循环中搜索Core Data中的对象?

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.")
                        }
                    }
                }
            }
        }
    }

2 个答案:

答案 0 :(得分:0)

当前的问题是您为request.predicate分配了一个值,但这样做无效。如果在执行提取之前将分配给它,则提取请求谓词才有效。它成为fetch的一部分,而fetch结果只包含与谓词匹配的对象。

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

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

  2. 不是将值赋给request.predicate,而是通过执行类似

    的操作过滤内存中的results数组
    let predicate = NSPredicate(format: "title = %@", "\(song.valueForProperty(MPMediaItemPropertyTitle))")
    let currentResults = results.filteredArrayUsingPredicate(predicate)
    

    这将为您提供仅包含与谓词匹配的歌曲的数组。这将比选项#1更快,但它仍然留下了您在这里获取所有歌曲的主要问题。这可能意味着每次调用此函数时都会将大量托管对象加载到内存中(假设用户有超过50,000首歌曲?)。它仍然不是一个好的解决方案。不幸的是,我不太了解MPMediaQuery建议采用更好的方法。

  3. 其中任何一个都应解决当前问题,但您需要解决更重要的概念问题。您正在比较两个寻找单个匹配的潜在大型集合。无论你如何处理它,都会占用大量的CPU时间或内存。

答案 1 :(得分:0)

找到我自己的解决方案。正如@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的帮助:Find key-value pair in an array of dictionaries