【问题标题】:Handle writeData method on NSFileHandle on main thread在主线程上处理 NSFileHandle 上的 writeData 方法
【发布时间】:2018-10-23 08:05:54
【问题描述】:

由于writeData 调用是同步的,当我们从主队列以外的不同线程调用 writeData 时,最好的使用方法是什么?

例如,调用 Web 服务来获取一些数据,并将 completionHandler 分配给 Web 服务调用。现在这个完成处理程序将在不同的线程上执行(而不是在主队列上)。

我看到我的应用程序在 writeData 方法上卡住了 5 到 6 分钟。这是我现在唯一可以怀疑的事情。

我尝试用dispatch_async(mainQueue) 包裹我的writeData 呼叫,但没有成功。

- (void) writeToFile: (NSString *) targetString
{
    //_loggingString holds the data, which keeps on accumulating as the user performs operations. At some point of time (callbacks from API's I call this method, to actually, write this string in the file and clear this string afterwards.)
    NSString *oldString = [_loggingString copy];

    _loggingString = [oldString stringByAppendingString:targetString];

    if (![[NSFileManager defaultManager]fileExistsAtPath:@"somePath"])
    {
        [[NSFileManager defaultManager]createFileAtPath:@"somePath" contents:nil attributes:nil];
    }

    NSFileHandle *fileHandle =  [NSFileHandle fileHandleForWritingAtPath:@"somePath"];

    [fileHandle seekToEndOfFile];

    [fileHandle writeData:[_loggingString dataUsingEncoding:NSUTF8StringEncoding]];

    _loggingString = @"";
}

【问题讨论】:

标签: ios objective-c iphone grand-central-dispatch


【解决方案1】:

您可以在后台线程中执行保存部分

- (void) writeToFile: (NSString *) targetString
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSString *oldString = [_loggingString copy];

    _loggingString = [oldString stringByAppendingString:targetString];

    if (![[NSFileManager defaultManager]fileExistsAtPath:@"somePath"])
    {
        [[NSFileManager defaultManager]createFileAtPath:@"somePath" contents:nil attributes:nil];
    }

    NSFileHandle *fileHandle =  [NSFileHandle fileHandleForWritingAtPath:@"somePath"];

    [fileHandle seekToEndOfFile];

    [fileHandle writeData:[_loggingString dataUsingEncoding:NSUTF8StringEncoding]];

    _loggingString = @"";

});
}

【讨论】:

  • 如果我在其中做任何事情,是否需要再次获取主队列?只是想知道......
  • 不,它不是必需的,我只是添加它以防万一您需要在任务完成后获取主线程。已更新答案并将其删除
【解决方案2】:

不推荐在主线程中进行文件写入操作。此外,默认全局队列也会出现性能问题,因为系统无法确定任务的优先级。

所以尝试创建4种类型的后台队列:

dispatch_queue_t GlobalUserInteractiveQueue(void) {
    return dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
}

dispatch_queue_t GlobalUserInitiatedQueue(void) {
    return dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);
}

dispatch_queue_t GlobalUtilityQueue(void) {
    return dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
}

dispatch_queue_t GlobalBackgroundQueue(void) {
    return dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
}

在你的代码中这样做:

创建自定义队列。 queue = dispatch_queue_create("customQueueName", NULL);

然后在 dispatch async 中编写代码

dispatch_async( queue ,
                   ^ {
                       // execute asynchronously
                       [fileHandle seekToEndOfFile];
                       [fileHandle writeData:[_loggingString dataUsingEncoding:NSUTF8StringEncoding]];

                   }); 

这里查看每个队列的工作过程: https://gist.github.com/ankitthakur/dd945a66924fbd697169

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多