1

我无法理解为 dispatch_io_read 函数调用提供给数据应用程序的偏移量变量。我看到文档声称偏移量是与数据对象基础的逻辑偏移量。查看 dispatch_data_apply 函数的源代码可以确认,对于第一次申请数据块,该变量总是从 0 开始,然后只是范围长度的总和。

我想我不明白这个变量的目的。我最初认为这是整个读取的偏移量,但事实并非如此。看来您必须跟踪读取的字节数和该数量的偏移量才能真正正确地在 libdispatch 中进行读取。

// Outside the dispatch_io_read handler...
char * currBufferPosition = destinationBuffer;

// Inside the dispatch_io_read handler...
dispatch_io_read(channel, fileOffset, bytesRequested, queue, ^(bool done, dispatch_data_t data, int error) {
  // Note: Real code would handle error variable.
  dispatch_data_apply(data, ^bool(dispatch_data_t region, size_t offset, const void * buffer, size_t size) {
    memcpy(currBufferPosition, buffer, size);
    currBufferPosition += size;
    return true;
  });
});

我的问题是:这是使用 dispatch_data_apply 返回的数据的正确方法吗?如果是这样,传递给应用程序处理程序的偏移变量的目的是什么?对我来说,文档似乎并不清楚。

4

1 回答 1

1

Adispatch_data_t是一个字节序列。字节可以存储在多个不连续的字节数组中。例如,字节 0-6 可以存储在数组中,然后字节 7-12 存储在内存中其他位置的单独数组中。

为了提高效率,该dispatch_data_apply函数允许您就地迭代这些数组(无需复制数据)。在每次调用您的“应用程序”时,您都会收到一个指向buffer参数中底层存储数组之一的指针。该size参数告诉您这个特定数组中有多少字节,并且该offset参数告诉您这个特定数组的第一个字节与整个dispatch_data_t.

例子:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_data_t aData = dispatch_data_create("Hello, ", 7, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
        dispatch_data_t bData = dispatch_data_create("world!", 6, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
        dispatch_data_t cData = dispatch_data_create_concat(aData, bData);

        dispatch_data_apply(cData, ^bool(dispatch_data_t  _Nonnull region, size_t offset, const void * _Nonnull buffer, size_t size) {
            printf("applying at offset %lu, buffer %p, size %lu, contents: [%*.*s]\n", (unsigned long)offset, buffer, (unsigned long)size, (int)size, (int)size, buffer);
            return true;
        });
    }
    return 0;
}

输出:

applying at offset 0, buffer 0x100407970, size 7, contents: [Hello, ]
applying at offset 7, buffer 0x1004087b0, size 6, contents: [world!]

好的,这就是offset争论的目的。现在这有什么关系dispatch_io_read

好吧,dispatch_io_read不会两次将相同的字节传递给您。一旦它传递了一些字节,它就会丢弃它们。下次它传递给你字节时,它们是新的、新读取的字节。如果你想要旧的字节,你必须自己保留它们。如果您想知道在当前调用回调之前给了多少旧字节,您必须自己保持这个计数。这不是offset争论的目的。

有可能在dispatch_io_read调用您时,它会将dispatch_data_t其字节存储在多个非连续数组中的 a 传递给您,因此当您调用dispatch_data_apply它时,您的应用程序会被多次调用,使用不同offset的 s 和buffers 和sizes。但是这些调用只能让您访问当前调用回调的新字节,而不是访问任何先前调用回调的旧字节。

于 2018-02-22T03:13:25.573 回答