libdispatch dispatch_data_apply 中的偏移量变量有什么意义?
What is the point of the offset variable in dispatch_data_apply for libdispatch?
我无法理解为 dispatch_io_read 函数调用提供给数据应用程序的偏移量变量。我看到 dispatch_data_apply 函数的 documentation claims the offset is the logical offset from the base of the data object. Looking at the source code 确认这个变量总是从 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 返回的数据的正确方法吗?如果是这样,传递给应用程序处理程序的偏移量变量的目的是什么?文档对我来说似乎不清楚。
一个dispatch_data_t
是一个字节序列。字节可以存储在多个 non-contiguous 字节数组中。例如,字节 0-6 可以存储在一个数组中,然后字节 7-12 存储在内存中其他地方的单独数组中。
为了提高效率,dispatch_data_apply
函数允许您迭代这些数组 in-place(无需复制数据)。在每次调用您的“applier”时,您都会收到一个指向 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
不会将相同的字节传递给您两次。一旦它传递给你一些字节,它就会丢弃它们。下次它向您传递字节时,它们是新鲜的 newly-read 字节。如果您想要旧字节,则必须将它们放在自己身边。如果你想知道在当前调用你的回调之前你有多少旧字节,你必须自己计算。这不是 offset
参数的目的。
有可能当 dispatch_io_read
调用你时,它传递给你一个 dispatch_data_t
,它已将其字节存储在多个 non-contiguous 数组中,所以当你调用 dispatch_data_apply
它,你的应用程序被多次调用,具有不同的 offset
s 和 buffer
s 和 size
s。但是这些调用只能让您访问当前调用回调的新字节,而不是之前调用回调的旧字节。
我无法理解为 dispatch_io_read 函数调用提供给数据应用程序的偏移量变量。我看到 dispatch_data_apply 函数的 documentation claims the offset is the logical offset from the base of the data object. Looking at the source code 确认这个变量总是从 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 返回的数据的正确方法吗?如果是这样,传递给应用程序处理程序的偏移量变量的目的是什么?文档对我来说似乎不清楚。
一个dispatch_data_t
是一个字节序列。字节可以存储在多个 non-contiguous 字节数组中。例如,字节 0-6 可以存储在一个数组中,然后字节 7-12 存储在内存中其他地方的单独数组中。
为了提高效率,dispatch_data_apply
函数允许您迭代这些数组 in-place(无需复制数据)。在每次调用您的“applier”时,您都会收到一个指向 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
不会将相同的字节传递给您两次。一旦它传递给你一些字节,它就会丢弃它们。下次它向您传递字节时,它们是新鲜的 newly-read 字节。如果您想要旧字节,则必须将它们放在自己身边。如果你想知道在当前调用你的回调之前你有多少旧字节,你必须自己计算。这不是 offset
参数的目的。
有可能当 dispatch_io_read
调用你时,它传递给你一个 dispatch_data_t
,它已将其字节存储在多个 non-contiguous 数组中,所以当你调用 dispatch_data_apply
它,你的应用程序被多次调用,具有不同的 offset
s 和 buffer
s 和 size
s。但是这些调用只能让您访问当前调用回调的新字节,而不是之前调用回调的旧字节。