3

如何在不同线程的后台执行某些操作,如果它在主线程上执行,它会阻塞我的应用程序的 UI。有人知道怎么做吗?

即使它在后台打印 NSLog 也可以。即使用户按下 HOME 按钮,我也想运行以下内容。在我的视图控制器中,我这样做了:

- (IBAction)btnStartClicked:(UIButton *)sender {
    [NSThread detachNewThreadSelector:@selector(StartBGTask) toTarget:self withObject:nil];
     }

-(void)StartBGTask{
    [[[UIApplication sharedApplication] delegate] performSelector:@selector(startThread)];  
  }

并且在 appDelegate.mi 中有这个方法

 -(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 秒的间隔打印 1 到 100 的整数。

4

3 回答 3

8

将这些属性添加到您的 .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;
}
于 2013-07-31T13:12:17.677 回答
6

Check GCD for more information.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //code in background
    });
于 2013-07-31T11:36:49.760 回答
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 就不会被阻塞。

于 2013-07-31T11:28:11.440 回答