【问题标题】:perform background task on different thread in iOS在 iOS 的不同线程上执行后台任务
【发布时间】:2013-07-31 09:45:20
【问题描述】:

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

即使它在后台打印 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 秒打印 1 到 100 的整数。

【问题讨论】:

  • 您的 for () {} 正在主队列中执行。而你使用 [NSThread sleepForTimeInterval:1],它不会阻塞你的 UI 吗?您停止了主队列。
  • 已编辑并包含更多详细信息,我尝试在不同线程上执行第二种方法,但按下主页按钮时它会停止后台任务。
  • 为什么不直接使用计时器。你甚至不需要把它放在后台线程上。
  • 正如我在下面所说的,我认为他的意思不是打印数字 1 到 100,这可能只是一些“线程的 helloWorld”,看看它是否有效。

标签: ios background-process nsthread


【解决方案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;
}

【讨论】:

    【解决方案2】:

    查看 GCD 了解更多信息。

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //code in background
        });
    

    【讨论】:

      【解决方案3】:

      实现您想要的非常简单的方法:

      -(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 配合使用,编译器不知道返回类型是什么。
      • 您能否更具体地说明可能存在的问题,或者提供一些来源?我曾经使用过类似的代码,没有发现任何问题/错误/泄漏。
      • 例如stackoverflow.com/questions/7017281/… 我看到这个是因为我唯一使用 performSelector 的时候是在使用字符串表示时。对于其他一切,我使用 GCD。作为第二点,在您的情况下,您将 nil 对象传递给不带参数的选择器。在这种情况下,您可以使用performSelector: 而不是performSelector:withObject:。实际上你甚至不需要 performSelector 在这里,你可以使用 dispatch_async() 并将你在方法中的内容作为一个块运行。
      • 首先,我明白你的意思,但我看不出链接的响应有任何问题,这种情况下,它没有返回任何东西或类似的东西。重点是performSelectorInBackground,它比 GCD 更容易阅读和使用。其次,performSelectorInBackground: 不存在,只有performSelectorInBackground:withObject:,这就是我在这种情况下通过 nil 的原因。
      • 根据我的经验,GCD 更容易阅读。要调用的方法就在那里,写在调用的上下文中,使用执行选择器,您需要找到源中其他地方的方法。此外,由于块捕获范围内的变量,您不必为传递参数而烦恼,块可以直接使用它们。在这种情况下,您甚至不需要执行任何操作,更好的解决方案是只使用计时器。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      • 2020-02-08
      • 2019-08-18
      相关资源
      最近更新 更多