在iOS中的不同线程上执行后台任务
如何在不同线程的后台执行某些操作,如果它在主线程上执行,它将阻止我的应用程序的UI。任何人有任何想法如何做到这一点?在iOS中的不同线程上执行后台任务
即使它在后台打印NSLog它会没事的。 即使用户按HOME按钮,我也想运行下面的东西。 在我的viewController我这样做:
- (IBAction)btnStartClicked:(UIButton *)sender {
[NSThread detachNewThreadSelector:@selector(StartBGTask) toTarget:self withObject:nil];
}
-(void)StartBGTask{
[[[UIApplication sharedApplication] delegate] performSelector:@selector(startThread)];
}
和appDelegate.m我有这个方法
-(void) startThread {
@autoreleasepool {
for (int i = 0; i < 100; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"current progress %d", i);
});
[NSThread sleepForTimeInterval:1];
}
}
}
它输出从1到100的整数上1秒的时间间隔。
这些属性添加到您的.h文件中
@property (nonatomic, strong) NSTimer *updateTimer;
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
现在更换btnStartClicked方法与此,
-(IBAction)btnStartClicked:(UIButton *)sender {
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:@selector(calculateNextNumber)
userInfo:nil
repeats:YES];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"Background handler called. Not running background tasks anymore.");
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
}
-(void)calculateNextNumber{
@autoreleasepool {
// this will be executed no matter app is in foreground or background
}
}
,如果你需要停止使用这种方法,
- (IBAction)btnStopClicked:(UIButton *)sender {
[self.updateTimer invalidate];
self.updateTimer = nil;
if (self.backgroundTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
i = 0;
}
一个非常简单的方式来完成你想要什么:
-(IBAction)btnStartClicked:(UIButton *)sender {
[self performSelectorInBackground:@selector(codeInBakground) withObject:nil];
}
-(void)codeInBakground
{
for (int i = 0; i < 100; i++) {
NSLog(@"current progress %d", i);
[NSThread sleepForTimeInterval:1]; //the code will print one number in each second, until 100
}
}
这样,你的主线程,和您的UI不会被阻止。
performSelector与ARC不能很好地协作,编译器不知道返回类型是什么。 – Abizern
你可以更具体地了解一个可能的问题,或者给出一些来源?我曾经使用过类似的代码,没有发现问题/错误/泄漏。 –
例如http://*.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown我看到这一点,因为我使用performSelector的唯一时间是当我使用一个字符串表示。对于其他所有我使用GCD的人。作为第二点,在你的情况下,你将一个无对象传递给一个不带参数的选择器。在这种情况下,你可以使用'performSelector:'而不是'performSelector:withObject:'。实际上,你甚至不需要执行这里的performSelector,你可以只使用dispatch_async()并将你在方法中的内容作为一个块运行。 – Abizern
查看GCD了解更多信息。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code in background
});
Your for(){}在主队列中执行。你使用[NSThread sleepForTimeInterval:1],是不是会阻止你的用户界面?你阻止你主队列。 –
编辑并包含更多细节,我试图执行第二种方法在不同的线程上执行,但当主页按钮被按下时,它停止后台任务。 –
为什么不使用计时器。你甚至不需要把它放在后台线程上。 – Abizern