向文件或socket写入数据非常类似于读取数据,配置描述符为写入操作后,创建一个 DISPATCH_SOURCE_TYPE_WRITE 类型的dispatch source,创建好之后,系统会调用事件处理器,让它开始向文件或socket写入数据。当你完成写入后,使用 dispatch_source_cancel 函数取消dispatch source。
写入数据也应该配置文件描述符使用非阻塞操作,虽然 dispatch_source_get_data 函数可以查看当前有多少可用写入空间,但这个值只是建议性的,而且在你执行写入操作时可能会发生变化。如果发生错误,写入数据到阻塞描述符,也会使事件处理器停止在执行中途,并阻止dispatch queue执行其它任务。串行queue会产生死锁,并发queue则会减少能够执行的任务数量。
下面是使用dispatch source写入数据到文件的例子,打开文件后,函数传递文件描述符到事件处理器。getData函数负责提供要写入的数据,在数据写入到文件之后,事件处理器取消dispatch source,阻止再次调用。此时dispatch source的拥有者需负责释放dispatch source。
#import <Foundation/Foundation.h>
static char *string = "这是一个测试::2017";
}
size_t getData(void *buffer, size_t bufferSize){
size_t length = strlen(string);
size_t loopCount = length;
if (bufferSize < length) {
loopCount = bufferSize;
}
for (int i = 0; i < loopCount; i++) {
((char*)buffer)[i] = string[i];
}
return loopCount;
}
dispatch_source_t createWriteOperationFileDescriptionDispatchSource(const char* filename)
{
//注意:open的第三个参数,仅在有O_CREAT标记时生效
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
(S_IRUSR | S_IWUSR | S_ISUID | S_ISGID));
if (fd == -1)
return NULL;
fcntl(fd, F_SETFL, O_NONBLOCK); // avoid blocking during the write.
//最好使用串行队列一个一个的写入
dispatch_queue_t queue = dispatch_queue_create("串行队列标记", NULL);
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
fd, 0, queue);
if (!writeSource)
{
close(fd);
return NULL;
}
dispatch_source_set_event_handler(writeSource, ^{
size_t bufferSize = getDataSize();
void* buffer = malloc(bufferSize);
size_t actual = getData(buffer, bufferSize);
write(fd, buffer, actual);
free(buffer);
// Cancel and release the dispatch source when done.
dispatch_source_cancel(writeSource);
});
dispatch_source_set_cancel_handler(writeSource, ^{
close(fd);
});
dispatch_resume(writeSource);
return (writeSource);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"==========描述符派发源===========");
createWriteOperationFileDescriptionDispatchSource("/Users/feinno/Desktop/test");
[[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
}
return 0;
}
写入数据也应该配置文件描述符使用非阻塞操作,虽然 dispatch_source_get_data 函数可以查看当前有多少可用写入空间,但这个值只是建议性的,而且在你执行写入操作时可能会发生变化。如果发生错误,写入数据到阻塞描述符,也会使事件处理器停止在执行中途,并阻止dispatch queue执行其它任务。串行queue会产生死锁,并发queue则会减少能够执行的任务数量。
下面是使用dispatch source写入数据到文件的例子,打开文件后,函数传递文件描述符到事件处理器。getData函数负责提供要写入的数据,在数据写入到文件之后,事件处理器取消dispatch source,阻止再次调用。此时dispatch source的拥有者需负责释放dispatch source。
#import <Foundation/Foundation.h>
static char *string = "这是一个测试::2017";
size_t getDataSize(){
}
size_t getData(void *buffer, size_t bufferSize){
size_t length = strlen(string);
size_t loopCount = length;
if (bufferSize < length) {
loopCount = bufferSize;
}
for (int i = 0; i < loopCount; i++) {
((char*)buffer)[i] = string[i];
}
return loopCount;
}
dispatch_source_t createWriteOperationFileDescriptionDispatchSource(const char* filename)
{
//注意:open的第三个参数,仅在有O_CREAT标记时生效
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
(S_IRUSR | S_IWUSR | S_ISUID | S_ISGID));
if (fd == -1)
return NULL;
fcntl(fd, F_SETFL, O_NONBLOCK); // avoid blocking during the write.
//最好使用串行队列一个一个的写入
dispatch_queue_t queue = dispatch_queue_create("串行队列标记", NULL);
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
fd, 0, queue);
if (!writeSource)
{
close(fd);
return NULL;
}
dispatch_source_set_event_handler(writeSource, ^{
size_t bufferSize = getDataSize();
void* buffer = malloc(bufferSize);
size_t actual = getData(buffer, bufferSize);
write(fd, buffer, actual);
free(buffer);
// Cancel and release the dispatch source when done.
dispatch_source_cancel(writeSource);
});
dispatch_source_set_cancel_handler(writeSource, ^{
close(fd);
});
dispatch_resume(writeSource);
return (writeSource);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"==========描述符派发源===========");
createWriteOperationFileDescriptionDispatchSource("/Users/feinno/Desktop/test");
[[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
}
return 0;
}