【问题标题】:dispatching to main queue always fails调度到主队列总是失败
【发布时间】:2012-06-10 00:42:37
【问题描述】:

我正在尝试通过 iOS 上的 GCD 将一些代码分派到主队列,但即使是最简单的测试也总是会失败。最后归结为:

static const int TICK_INTERVAL = 1;

#pragma UIApplicationDelegate implementation

- (void) doTick
{
    if (![NSThread isMainThread])
    {
        NSLog(@"Trying to dispatch . . .");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"test . . .");
        });
    }
}

- (void) startUpdate
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        timer_ = [NSTimer
                  scheduledTimerWithTimeInterval:TICK_INTERVAL
                  target:self
                  selector:@selector(backgroundUpdate)
                  userInfo:nil
                  repeats:NO
                  ];

        [[NSRunLoop currentRunLoop]
         addTimer:timer_
         forMode:NSRunLoopCommonModes
         ];

        [[NSRunLoop currentRunLoop] run];
    });

    UIBackgroundTaskIdentifier back =
    [[UIApplication sharedApplication]
     beginBackgroundTaskWithExpirationHandler:^{
         [self doTick];
         [[UIApplication sharedApplication]
          endBackgroundTask:back
          ];
     }];
}

-(void)backgroundUpdate
{
    [self doTick];

    UIBackgroundTaskIdentifier back =
    [[UIApplication sharedApplication]
     beginBackgroundTaskWithExpirationHandler:^{
         [self doTick];
         [[UIApplication sharedApplication]
          endBackgroundTask:back
          ];
     }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            timer_ = [NSTimer
                     scheduledTimerWithTimeInterval:TICK_INTERVAL
                     target:self
                     selector:@selector(backgroundUpdate)
                     userInfo:nil
                     repeats:NO
                     ];

            [[NSRunLoop currentRunLoop]
             addTimer:timer_
             forMode:NSRunLoopCommonModes
             ];

            [[NSRunLoop currentRunLoop] run];
        });
}

- (id) init
{   
    self = [super init];
    [self startUpdate];
    return self;
}

那是我的AppDelegate。 我希望 NSLog 在主线程中执行以记录上面的测试文本,但没有任何反应。 dispatch_sync 代码永远等待,我放置在块中的断点永远不会到达。

我确保代码不在主线程中执行。在使用dispatch_sync 进行测试之前,我在我的应用程序中尝试了dispatch_async,结果当然基本相同:什么都没有发生(没有阻塞)。

有趣的是,它似乎不适用于主队列,其他队列(当前队列、全局队列)似乎工作得很好。

我在我的应用中使用 Phonegap (Cordova),如果这有任何意义的话。

有任何想法?

非常感谢!

【问题讨论】:

  • 使用[NSThread isMainThread] 测试是否在主线程上
  • 我做到了。请看我改进的例子。

标签: objective-c ios queue grand-central-dispatch dispatch


【解决方案1】:

您永远不应该将在队列上执行的任务dispatch_sync 转移到同一个队列。这可以保证在任何串行队列(如主队列)上死锁,并且在并发队列上是个坏主意。有关详细信息,请参阅Apple's Concurrency Programming Guide。由于应用程序委托的 init 方法在主线程上运行,dispatch_sync 到主队列会导致死锁。

dispatch_async 到主队列只要你在主线程上运行正常的 NSRunLoop 就可以工作。当然,您的 NSLog(@"test . . .") 可能会在您的应用程序委托的 init 方法完成之后执行。

【讨论】:

  • 完全正确,虽然我不知道为什么 dispatch_async 会失败。你确定 -init 被调用了吗?
  • 从技术上讲,您不应该从通过dispatch_sync 发送到同一队列的块中的dispatch_sync。我想dispatch_async 内的dispatch_sync 会很好,即使它是同一个队列。
  • 感谢您的提示,我显然未能将其煮沸。但是,我确信问题不在于我的代码在主队列中执行。请查看更新后的代码进行解释。
  • 修改后的代码示例非常不典型。但是,当我将其剪切并粘贴到模板 iOS 空应用程序中时,它确实可以工作并重复显示“尝试调度”和“测试”消息。因此,任何错误都在示例代码之外,并且在 -init 之后主线程上发生的任何事情中。
猜你喜欢
  • 2020-03-13
  • 1970-01-01
  • 2019-07-02
  • 2018-06-26
  • 2023-03-30
  • 1970-01-01
  • 2018-03-15
  • 2016-02-09
  • 1970-01-01
相关资源
最近更新 更多