xcode 如何停止在后台执行选择器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4992472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to stop performing selector in background?
提问by Alex
I have some class A. In this class i have a method,
which calls [self performSelectorInBackground:...]
. And it starts downloading
some info from internet.
我有一些 A 类。在这个类中,我有一个方法,它调用 [ self performSelectorInBackground:...]
。它开始从互联网下载一些信息。
After i tap Home button, then enter the app again, this background method keeps working. So, if i call this method again, i have bad_access, because background method is already working and i call it twice.
在我点击主页按钮,然后再次进入应用程序后,此后台方法继续有效。所以,如果我再次调用这个方法,我有 bad_access,因为后台方法已经在工作,我调用了两次。
Can i stop performing selector in background of the class A? For example in my applicationDidEnterBackground? Or can i check, if selector is performing or something?
我可以停止在 A 类后台执行选择器吗?例如在我的 applicationDidEnterBackground? 或者我可以检查一下,选择器是否正在执行或什么的?
I found couple things like
我发现了一些事情,比如
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:a];
[NSObject cancelPreviousPerformRequestsWithTarget:a selector:@selector(startDownload) object:nil];
But they didn't work for me. So
但他们对我不起作用。所以
my objAppDelegate:
我的 objAppDelegate:
@inteface ObjAppDelegate
{
A *a;
}
@implementation ObjAppDelegate
{
-(void)applicationDidEnterBackground:(UIApplication *)application
{
//or it can be didBecomeActive..
//here. check if background task of class A is running, or just stop it ??
}
}
@implementation A
{
//some timer, or event, etc.
-(void)startDownload
{
[self performSelectorInBackground:@selector(runBackgroundTask) withObject:nil];
}
-(void)runBackgroundTask
{
//some network stuff..
}
}
i did it like this:
我是这样做的:
threadForDownload = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil]; [threadForDownload start]; [self performSelector:@selector(startDownload) onThread:threadForDownload withObject:nil waitUntilDone:NO];
(void)threadMain:(id)data { NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (YES) { [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; }
[pool release]; }
In my startDownload method i look at activity indicator to check, whether startDownload is already running..
在我的 startDownload 方法中,我查看活动指示器以检查 startDownload 是否已经在运行。
-(void)startDownload
{
if (![[UIApplication sharedApplication] isNetworkActivityIndicatorVisible]) // flag..
{
//....
}
}
// I make visible networkActivityIndicator every time i start downloading
// 每次开始下载时,我都会使 networkActivityIndicator 可见
回答by Nikita Rybak
You can easily create a BOOL
instance variable to determine whether background task is active.
您可以轻松创建一个BOOL
实例变量来确定后台任务是否处于活动状态。
BOOL isBackgroundTaskRunning;
Then in runBackgroundTask
然后在 runBackgroundTask
if (isBackgroundTaskRunning) {
// already running
return;
}
isBackgroundTaskRunning = TRUE;
...
isBackgroundTaskRunning = FALSE;
回答by JeremyP
Here's what to do:
以下是该怎么做:
- the background task saves its thread to a property somewhere using NSThread currentThread
- the background task periodically checks the thread's isCancelledproperty.
- the main thread sends cancelto the thread object saved by the background thread in step 1.
- On exit, the background thread sets the property to nil.
- 后台任务使用NSThread currentThread将其线程保存到某个属性
- 后台任务会定期检查线程的isCancelled属性。
- 主线程向步骤1中后台线程保存的线程对象发送取消。
- 退出时,后台线程将该属性设置为 nil。
All of the operations on the property used to store the thread in have to be protected by @synchronized
or equivalent to prevent the main thread from sending cancel
to a deallocated thread object.
用于存储线程的属性上的所有操作都必须受到保护@synchronized
或等效,以防止主线程发送cancel
到释放的线程对象。
The background thread can't do IO operations that block for more than a short period of time. In particular, synchronous downloading of URLs using NSURLConnection is out. If you are using NSURLConnection, you'll want to move to the asynchronous methods and a run loop (arguably, in that case, you can do away with the background thread altogether). If you are using POSIX level IO, use poll()
with a timeout.
后台线程不能执行阻塞时间超过短时间的 IO 操作。特别是,使用 NSURLConnection 的 URL 同步下载已经过时了。如果您正在使用 NSURLConnection,您将需要转向异步方法和运行循环(可以说,在这种情况下,您可以完全取消后台线程)。如果您使用 POSIX 级别的 IO,请使用poll()
超时。
回答by emix
I don't think that it would be save to force the interruption of a method. What you can do is to change the state of your object and check that state inside your method implementation to early return in case of a cancel (but don't forget to release allocated objects).
我不认为强制中断一个方法会有什么好处。您可以做的是更改对象的状态并检查方法实现中的状态以在取消的情况下提前返回(但不要忘记释放分配的对象)。
This is how NSOperationQueue works. From the documentation:
这就是 NSOperationQueue 的工作原理。从文档:
Cancelling an operation does not immediately force it to stop what it is doing. Although respecting the value returned by the isCancelled is expected of all operations, your code must explicitly check the value returned by this method and abort as needed.
取消操作不会立即强制它停止正在执行的操作。尽管所有操作都期望尊重 isCancelled 返回的值,但您的代码必须显式检查此方法返回的值并根据需要中止。
回答by Alexsander Akers
Run the method in a background thread, and keep a record of the NSThread
. Then later, you can just end the thread.
在后台线程中运行该方法,并记录NSThread
. 然后,您可以结束线程。