Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/111.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Objective-C-等待另一个线程上的调用返回,然后继续_Ios_Objective C_Multithreading_Grand Central Dispatch - Fatal编程技术网

Ios Objective-C-等待另一个线程上的调用返回,然后继续

Ios Objective-C-等待另一个线程上的调用返回,然后继续,ios,objective-c,multithreading,grand-central-dispatch,Ios,Objective C,Multithreading,Grand Central Dispatch,在我的iOS应用程序中,我有一个数据库调用,需要一些时间才能完成。进行此操作时,屏幕上会显示一个微调器。我在应用程序崩溃时遇到一个错误,“com.myapp未能及时恢复”,因此它似乎正在主线程上运行数据库调用,从而导致问题 现行代码 -(void)timeToDoWork { ... [CATransaction flush]; [[DatabaseWorker staticInstance] doWork]; //Additional UI stuff he

在我的iOS应用程序中,我有一个数据库调用,需要一些时间才能完成。进行此操作时,屏幕上会显示一个微调器。我在应用程序崩溃时遇到一个错误,“com.myapp未能及时恢复”,因此它似乎正在主线程上运行数据库调用,从而导致问题

现行代码

-(void)timeToDoWork
{
    ...
    [CATransaction flush];

    [[DatabaseWorker staticInstance] doWork];

    //Additional UI stuff here
    ...

    if([self->myReceiver respondsToSelector:self->myMessage])
    {
        [self->myReceiver performSelector:self->myMessage];
    }
}
要在后台线程上执行doWork函数,我可以使用Grand Central Dispatch:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    [[DatabaseWorker staticInstance] doWork];
});
但是,如何防止执行继续,直到完成?我是否应该在doWork调用之后结束该方法,并将其下面的所有内容移动到新函数

样品

-(void)timeToDoWork
{
    ...
    [CATransaction flush];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        [[DatabaseWorker staticInstance] doWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self doneDoingWork];
        });
    });
}

-(void)doneDoingWork
{
    //Additional UI stuff here
    ...

    if([self->myReceiver respondsToSelector:self->myMessage])
    {
        [self->myReceiver performSelector:self->myMessage];
    }
}

有更好的方法吗?

我认为您应该在DatabaseWorker中使用委托,并且方法doWork始终在后台运行,因此当工作人员完成工作时,它会告诉其委托人工作已经完成。必须在主线程中调用委托方法

如果有许多对象需要知道DatabaseWorker何时完成,而不是使用委托,那么我将使用通知

编辑:

在DatabaseWorker类中,您需要实现方法
doWork
,如下所示:

- (void) doWork{
         dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
         dispatch_async(queue, ^{
             //Do the work.
             dispatch_async(dispatch_get_main_queue(), ^{
                 [self.delegate finishWork];
             });
         });
}
在实现timeTodoWork的类中:

-(void)timeToDoWork
{
    ...
    [CATransaction flush];

    [[DatabaseWorker staticInstance] setDelegate:self];
    [[DatabaseWorker staticInstance] doWork];
}

#pragma mark DatabaseWorkerDelegate
- (void) finishWork{
    //Additional UI stuff here
    ...

    if([self->myReceiver respondsToSelector:self->myMessage])
    {
        [self->myReceiver performSelector:self->myMessage];
    }
}
您还可以使用:

[self performSelectorInBackground:@selector(doWorkInBackground) withObject:nil];
而不是:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
         dispatch_async(queue, ^{
             //Do the work.
});
并添加一个方法:

- (void) doWorkInBackground{
       //Do the work
        [self.delegate performSelectorOnMainThread:@selector(finishWork) withObject:nil waitUntilDone:NO];
}

我认为您应该在DatabaseWorker中使用一个委托,并且方法doWork始终在后台运行,因此当工作人员完成工作时,它会告诉其委托人工作已经完成。必须在主线程中调用委托方法

如果有许多对象需要知道DatabaseWorker何时完成,而不是使用委托,那么我将使用通知

编辑:

在DatabaseWorker类中,您需要实现方法
doWork
,如下所示:

- (void) doWork{
         dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
         dispatch_async(queue, ^{
             //Do the work.
             dispatch_async(dispatch_get_main_queue(), ^{
                 [self.delegate finishWork];
             });
         });
}
在实现timeTodoWork的类中:

-(void)timeToDoWork
{
    ...
    [CATransaction flush];

    [[DatabaseWorker staticInstance] setDelegate:self];
    [[DatabaseWorker staticInstance] doWork];
}

#pragma mark DatabaseWorkerDelegate
- (void) finishWork{
    //Additional UI stuff here
    ...

    if([self->myReceiver respondsToSelector:self->myMessage])
    {
        [self->myReceiver performSelector:self->myMessage];
    }
}
您还可以使用:

[self performSelectorInBackground:@selector(doWorkInBackground) withObject:nil];
而不是:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
         dispatch_async(queue, ^{
             //Do the work.
});
并添加一个方法:

- (void) doWorkInBackground{
       //Do the work
        [self.delegate performSelectorOnMainThread:@selector(finishWork) withObject:nil waitUntilDone:NO];
}

您收到的错误表明您正在
应用程序中执行某些操作:使用选项完成启动:
applicationdDecomeAction:
或启动周期中的其他地方,这些地方花费的时间太长,应用程序将被启动监视器计时器终止。最重要的是,您必须尽快从这些方法返回。我不确定你的代码在发布周期中的位置;但这一解释似乎是合理的

有各种各样的方法来解决这个问题;但是,正如您所指出的,将冗长的流程从主队列中移除是第一步。如果不知道什么主要队列对象(例如UI)依赖于此数据库事务,我认为您建议的解决方案非常好。即,将工作分派到后台队列;完成后,将剩余的UI工作分派到主队列


有人在其他地方建议代表们作为解决办法。这也是可行的,尽管您仍然需要关注调用委托方法的队列。

您收到的错误表明您正在
应用程序中执行某些操作:使用选项完成启动:
应用程序IDBecomeAction:
或启动周期中的其他地方长,应用程序将被启动监视程序计时器终止。最重要的是,您必须尽快从这些方法返回。我不确定你的代码在发布周期中的位置;但这一解释似乎是合理的

有各种各样的方法来解决这个问题;但是,正如您所指出的,将冗长的流程从主队列中移除是第一步。如果不知道什么主要队列对象(例如UI)依赖于此数据库事务,我认为您建议的解决方案非常好。即,将工作分派到后台队列;完成后,将剩余的UI工作分派到主队列

有人在其他地方建议代表们作为解决办法。这也是可行的,尽管您仍然需要考虑调用委托方法的队列。

您也可以使用块。 e、 g

然后像这样使用它:

[[DatabaseWorker staticInstance] doWorkWithCompletionHandler:^{
    // update your UI here, after the db operation is completed.
}];
附言。 复制
处理程序
块可能是个好主意。

您也可以使用块。 e、 g

然后像这样使用它:

[[DatabaseWorker staticInstance] doWorkWithCompletionHandler:^{
    // update your UI here, after the db operation is completed.
}];
附言。
复制
处理程序
块可能是个好主意。

阻止主线程中的执行继续是个坏主意。iOS将终止您的应用程序,因为主线程应始终与运行循环一起工作。 我建议你用以下方法来处理你的问题: 写一个“储物柜”。让它显示一些带有动画微调器的视图,而不显示任何按钮。 当您开始分派异步操作时,只需将它放在前面,让它与运行循环一起工作。
异步操作完成后,关闭锁柜

阻止主线程中的执行继续是个糟糕的主意。iOS将终止您的应用程序,因为主线程应始终与运行循环一起工作。 我建议你用以下方法来处理你的问题: 写一个“储物柜”。让它显示一些带有动画微调器的视图,而不显示任何按钮。 当您开始分派异步操作时,只需将它放在前面,让它与运行循环一起工作。
异步操作完成后,关闭锁柜

因此,我将执行类似[[DatabaseWorker staticInstance]performSelectorInBackground:doWork with Object:nil]的操作,而不是dispatch_async;然后在doWork结束时,它将执行SelectorOnMainThread以点击doneDoingWork?因此,我将执行类似于[[DatabaseWorker staticInstance]performSelectorInBackground:doWork with Object:nil]的操作,而不是dispatch_async];然后在doWork结束时,点击doneDoingWork将执行SelectorNoMainThread?我认为您的解决方案看起来不错。很难决定什么是“更好”的方法。您可以在某些共享标志变量上使用KVO,但我