我无法使NSFetchRequest fetchBatchSize
正常工作。我正在测试:
Objective-C中的行为按预期工作。返回的fetchResults
数组正确执行20个批处理中的获取请求,因为在返回的数组中访问了项目。使用Core Data工具或使用-com.apple.CoreData.SQLDebug
标志进行性能分析会显示此行为。
Swift中的行为显示已损坏。执行获取请求并将其存储在fetchResults
变量中后,将自动批量生成一系列获取请求,而无需任何其他代码访问返回的fetchResults
数组。也许Swift正在制作数组的副本或以某种方式访问数组中的每个元素,从而触发整个数组的自动批处理?
com.apple.CoreData.SQLDebug 3
选项将每个批量提取请求显示为:
2017-03-10 20:57:23.698 TestApp[25937:5366493] CoreData: annotation: Bound intarray _Z_intarray0
2017-03-10 20:57:23.699 TestApp[25937:5366493] CoreData: details: Bound intarray value 1 at 0
2017-03-10 20:57:23.700 TestApp[25937:5366493] CoreData: details: Bound intarray value 2 at 1
2017-03-10 20:57:23.700 TestApp[25937:5366493] CoreData: details: Bound intarray value 3 at 2
2017-03-10 20:57:23.700 TestApp[25937:5366493] CoreData: details: Bound intarray value 4 at 3
…
2017-03-10 20:57:23.728 TestApp[25937:5366493] CoreData: details: Bound intarray value 20 at 19
2017-03-10 20:57:23.728 TestApp[25937:5366493] CoreData: annotation: Bound intarray values.
2017-03-10 20:57:23.728 TestApp[25937:5366493] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME FROM ZITEM t0 WHERE t0.Z_PK IN (SELECT * FROM _Z_intarray0) LIMIT 20
2017-03-10 20:57:23.730 TestApp[25937:5366493] CoreData: annotation: sql connection fetch time: 0.0316s
2017-03-10 20:57:23.730 TestApp[25937:5366493] CoreData: annotation: fetch using NSSQLiteStatement <0x60800008dc00> on entity 'Item' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME FROM ZITEM t0 WHERE t0.Z_PK IN (SELECT * FROM _Z_intarray0) LIMIT 20' returned 20 rows with values: (
"<Item: 0x6080000aa380> (entity: Item; id: 0x40000b <x-coredata://7B347406-2EDA-465D-B002-B392D3DE9CF4/Item/p1> ; data: <fault>)",
…
"<Item: 0x6080000aa740> (entity: Item; id: 0x500000b <x-coredata://7B347406-2EDA-465D-B002-B392D3DE9CF4/Item/p20> ; data: <fault>)"
)
这可能会发生什么?只要在Objective-C中执行获取请求,返回的数组就可以传递给Swift代码,并且在访问数组元素时批处理工作正常。只有在Swift中执行获取请求时,行为才是错误的。
目标-C:
- (NSArray<Item *> *)fetch {
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Item"];
request.fetchBatchSize = 20;
NSArray *fetchResults = [self.context executeFetchRequest:request error:nil];
return fetchResults;
}
夫特:
func fetch() -> [Item] {
let request = NSFetchRequest<Item>(entityName: "Item")
request.fetchBatchSize = 20
let fetchResults = (try? self.context.fetch(request)) ?? []
return fetchResults
}
执行获取并将结果存储在属性中。
var items: [Item]!
func fetchItems() {
if let fetcher = SwiftFetcher(context: document.managedObjectContext) {
items = fetcher.fetch()
}
}
我当前的解决方法涉及编写自定义FetchedBatchArray类,该类包装Swift数组并在访问数组中的元素时构造和执行获取请求,在从存储中获取对象时填充后备数组。这提供了一种实现类似于使用NSFetchRequest
fetchBatchSize
的提取行为的方法,但它并不需要在Objective-C中编写任何内容。它还避免了在连接到Swift时遇到这个bug的微妙之处。
答案 0 :(得分:0)
Swift Array
类型是一种值类型,从NSArray
到Swift数组的自动桥接基本上遍历整个数组并将元素复制到新的Swift数组中。如果从调试器中调用po array
,则会发生同样的情况。
如果将fetch
方法的返回类型保留为NSArray<Item>
,则不需要迭代这些元素。