And*_*kha 12 cocoa-touch grand-central-dispatch ios
这是我的问题.当我的应用程序进入后台时,我希望它在一段时间后执行一个功能.这就是我做的:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
isRunningInBackground = YES;
taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
int64_t delayInSeconds = 30;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
[self doSomething];
});
}
- (void)doSomething
{
NSLog(@"HELLO");
}
Run Code Online (Sandbox Code Playgroud)
taskIdentifier 变量在myAppDelegate.h文件中声明如下:
UIBackgroundTaskIdentifier taskIdentifier;
Run Code Online (Sandbox Code Playgroud)
一切都按照预期的方式工作,我看到控制台在30秒后就打印了HELLO.但是doSomething如果应用程序进入前景直到30秒结束,我不想被执行.所以我需要取消它.这就是我这样做的方式:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
isRunningInBackground = NO;
[self stopBackgroundExecution];
}
- (void)stopBackgroundExecution
{
[[UIApplication sharedApplication] endBackgroundTask:taskIdentifier];
taskIdentifier = UIBackgroundTaskInvalid;
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是它没有取消doSomething,它仍然执行.我究竟做错了什么?如何取消该功能?
Ole*_*yuk 12
有点不同的方法
OK,因此,收集所有答案,以及可能的解决方案,对于这种情况(保持简单性)似乎是最好的方法是在需要时performSelector:withObject:afterDelay:通过cancelPreviousPerformRequestsWithTarget:调用来调用和取消它.就我而言 - 就在安排下一次延迟通话之前:
[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(myDelayedMethod) object: self];
[self performSelector:@selector(myDelayedMethod) withObject: self afterDelay: desiredDelay];
Run Code Online (Sandbox Code Playgroud)
这个答案必须在这里发布:取消dispatch_after()方法?,但这是一个副本(实际上不是).无论如何,这是一个google返回"dispatch_after cancel"的地方,所以......
这个问题非常基础,我确信有些人想要一个真正通用的解决方案,而不需要使用各种平台特定的方法,如runloop定时器,实例包含的布尔值和/或重块魔术.GCD可以用作常规C库,并且可能根本没有计时器.
幸运的是,有一种方法可以取消任何生命周期方案中的任何调度块.
struct async_handle {
char didFire; // control block did fire
char shouldCall; // control block should call payload
char shouldFree; // control block is owner of this handle
};
static struct async_handle *
dispatch_after_h(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t payload)
{
struct async_handle *handle = malloc(sizeof(*handle));
handle->didFire = 0;
handle->shouldCall = 1; // initially, payload should be called
handle->shouldFree = 0; // and handles belong to owner
payload = Block_copy(payload);
dispatch_after(when, queue, ^{
// this is a control block
printf("[%p] (control block) call=%d, free=%d\n",
handle, handle->shouldCall, handle->shouldFree);
handle->didFire = 1;
if (handle->shouldCall) payload();
if (handle->shouldFree) free(handle);
Block_release(payload);
});
return handle; // to owner
}
void
dispatch_cancel_h(struct async_handle *handle)
{
if (handle->didFire) {
printf("[%p] (owner) too late, freeing myself\n", handle);
free(handle);
}
else {
printf("[%p] (owner) set call=0, free=1\n", handle);
handle->shouldCall = 0;
handle->shouldFree = 1; // control block is owner now
}
}
Run Code Online (Sandbox Code Playgroud)
而已.
重点是"所有者"应该收集句柄,直到它不再需要它们为止.dispatch_cancel_h()作为句柄的[可能延迟]析构函数.
C所有者示例:
size_t n = 100;
struct after_handle *handles[n];
for (size_t i = 0; i < n; i++)
handles[i] = dispatch_after_h(when, queue, ^{
printf("working\n");
sleep(1);
});
...
// cancel blocks when lifetime is over!
for (size_t i = 0; i < n; i++) {
dispatch_cancel_h(handles[i]);
handles[i] = NULL; // not our responsibility now
}
Run Code Online (Sandbox Code Playgroud)
Objective-C ARC示例:
- (id)init
{
self = [super init];
if (self) {
queue = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);
handles = [[NSMutableArray alloc] init];
}
return self;
}
- (void)submitBlocks
{
for (int i = 0; i < 100; i++) {
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (random() % 10) * NSEC_PER_SEC);
__unsafe_unretained id this = self; // prevent retain cycles
struct async_handle *handle = dispatch_after_h(when, queue, ^{
printf("working (%d)\n", [this someIntValue]);
sleep(1);
});
[handles addObject:[NSValue valueWithPointer:handle]];
}
}
- (void)cancelAnyBlock
{
NSUInteger i = random() % [handles count];
dispatch_cancel_h([handles[i] pointerValue]);
[handles removeObjectAtIndex:i];
}
- (void)dealloc
{
for (NSValue *value in handles) {
struct async_handle *handle = [value pointerValue];
dispatch_cancel_h(handle);
}
// now control blocks will never call payload that
// dereferences now-dangling self/this.
}
Run Code Online (Sandbox Code Playgroud)
笔记:
由于iOS 10和Swift 3 GCDDispatchWorkItem是可取消的。只需为工作项保留一个实例并检查它是否尚未取消,然后取消它:
// Create a work item
let work = DispatchWorkItem {
print("Work to be done or cancelled")
}
// Dispatch the work item for executing after 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: work)
// Later cancel the work item
if !work.isCancelled {
work.cancel()
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10097 次 |
| 最近记录: |