我无法使 NSFetchRequest 的 fetchBatchSize
正常工作。我正在测试:
- Swift 3.0、Xcode 8.2.1、macOS 10.12 SDK、OS X 10.11.6
- Swift 3.1、Xcode 8.3 b4、macOS 10.12 SDK、macOS 10.12.3
Objective-C 中的行为按预期工作。返回的 fetchResults
数组在访问返回数组中的项目时以 20 个为一组正确执行提取请求。使用 Core Data 仪器或使用 -com.apple.CoreData.SQLDebug
标志进行分析显示了这种行为。
Swift 中的行为出现问题。 在执行提取请求并将其存储在 fetchResults
变量中后,会自动以 20 个为一组自动发出一系列提取请求,而不会访问返回的 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 中执行 fetch 请求时行为不正确。
Objective-C :
- (NSArray<Item *> *)fetch {
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Item"];
request.fetchBatchSize = 20;
NSArray *fetchResults = [self.context executeFetchRequest:request error:nil];
return fetchResults;
}
swift :
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 时遇到此错误的微妙之处。
最佳答案
swift Array
type是值类型,自动桥接自NSArray
到 Swift 数组基本上遍历整个数组并将元素复制到一个新的 Swift 数组中。如果你调用 po array
也会发生同样的事情。从调试器。
如果保留 fetch
的返回类型方法为 NSArray<Item>
,元素将不需要迭代。
关于objective-c - NSFetchRequest 的 fetchBatchSize 导致在 Swift 中立即获取所有批处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42731226/