objective-c - NSFetchRequest 的 fetchBatchSize 导致在 Swift 中立即获取所有批处理

标签 objective-c swift macos core-data

我无法使 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 数组并在访问数组中的元素时构造和执行提取请求,并在从存储中提取对象时填充后备数组。这提供了一种实现类似于使用 NSFetchRequestfetchBatchSize 的类似抓取行为的方法,但它不需要用 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/

相关文章:

objective-c - 启用 AppSand 盒时如何从 USB 大容量存储设备读取数据

objective-c - x代码 : Passing a Label text into a custom added subview

objective-c - .Net Unicode 编码在 Objective-C 中的等价物是什么?

ios - 如何添加过滤器以从 iOS 中录制的音频文件中去除噪音

ios - 如何创建一个 "live"图标,就像在 Mac OS 中一样,在其顶角有一个红色圆圈?

iphone - 将数组从 NSObject 传递到 View Controller

ios - 如何将长按手势识别器添加到 tableview 单元格内的按钮?

objective-c - 如何使用 Apple Symbols 字体中的字形?

Macos Catalina 更新后出现错误 : unable to run colorls

swift - 泛型的尾随闭包?