我试图通过检查自上次检查后是否有任何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.")
}
}
}
}
}
}
答案 0 :(得分:0)
当前的问题是您为request.predicate
分配了一个值,但这样做无效。如果在执行提取之前将分配给它,则提取请求谓词才有效。它成为fetch的一部分,而fetch结果只包含与谓词匹配的对象。
解决此特定问题有几种可能性:
在循环内分配谓词后,在循环中获取核心数据。这将获得您期望的结果。然而,它也将非常效率低下并且不会很好地扩展。获取请求是相对昂贵的操作,因此您可能会发现您花费了大量时间来执行这些操作。
不是将值赋给request.predicate
,而是通过执行类似
results
数组
let predicate = NSPredicate(format: "title = %@", "\(song.valueForProperty(MPMediaItemPropertyTitle))")
let currentResults = results.filteredArrayUsingPredicate(predicate)
这将为您提供仅包含与谓词匹配的歌曲的数组。这将比选项#1更快,但它仍然留下了您在这里获取所有歌曲的主要问题。这可能意味着每次调用此函数时都会将大量托管对象加载到内存中(假设用户有超过50,000首歌曲?)。它仍然不是一个好的解决方案。不幸的是,我不太了解MPMediaQuery
建议采用更好的方法。
其中任何一个都应解决当前问题,但您需要解决更重要的概念问题。您正在比较两个寻找单个匹配的潜在大型集合。无论你如何处理它,都会占用大量的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