Ios Objective-C-等待另一个线程上的调用返回,然后继续
在我的iOS应用程序中,我有一个数据库调用,需要一些时间才能完成。进行此操作时,屏幕上会显示一个微调器。我在应用程序崩溃时遇到一个错误,“com.myapp未能及时恢复”,因此它似乎正在主线程上运行数据库调用,从而导致问题 现行代码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
-(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,但我