У dispatch_async есть задержка где-то, не могу найти где.есть ли проблема с NSLog? - PullRequest
5 голосов
/ 08 августа 2011

Итак, у меня есть этот код:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

//Bunch of code

NSLog(@"Test");

});

, который запускается и немедленно возвращает nslog.Но результаты кода появляются только на экране с задержкой в ​​несколько секунд.Есть ли проблема с использованием nslog, что означает, что он вызывается раньше, чем обычно, что делает его быстрым, хотя на самом деле это не так.Я запутался в том, откуда берется эта задержка, поскольку NSLog находится в конце всего кода, который выполняется тогда.

Кроме того, еще одно решение моей проблемы - возможно ли получить NSLogкогда каждый метод вызывается (немного похоже на NSZombiesEnabled, я полагаю), чтобы я мог убедиться, что нет ни одного бита, который я не заметил, занимая приятное время отклика моего приложения?

Ответы [ 3 ]

11 голосов
/ 09 августа 2011

UIKit не является потокобезопасным.Любые звонки, которые вы делаете, которые влияют на ваш пользовательский интерфейс, должны быть сделаны в главном потоке, иначе вы получите странное, непредсказуемое поведение.Пример:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Background code that doesn't need to update the UI here

    dispatch_async(dispatch_get_main_queue(), ^{
        // UI code here
    });
});
11 голосов
/ 09 августа 2011

Недавно у меня была похожая проблема. Скорее всего, ваши отложенные обновления - это то, что вы делаете в пользовательском интерфейсе. И вот проблема: вы не работаете в главном потоке приложения (также называемом потоком пользовательского интерфейса). Поэтому, что бы вы ни изменили в пользовательском интерфейсе, оно на самом деле не будет видимо до тех пор, пока ... не появится ощущение, что это происходит при перерисовке, вызванной чем-то другим в приложении.

Что вам нужно сделать, так это поместить в очередь блоков графические обновления в потоке пользовательского интерфейса, например:

dispatch_async(dispatch_get_main_queue(), ^{
        // Do GUI stuff.
    });

Иногда ваш блок может быть большим или просто использовать код, который ранее выполнялся в главном потоке, поэтому трудно переместить все это в определенное место, чтобы запустить его в главной очереди. Для этих ситуаций поставьте в очередь принудительное обновление в потоке пользовательского интерфейса в конце вашего блока:

dispatch_async(dispatch_get_main_queue(), ^{
        [self.somewidget setNeedsDisplay];
        [self.view setNeedsDisplay];
        [self.dontforgetme setNeedsDisplay];
    });

Что касается вашего " приложения, занимающего приятное время отклика моего приложения ", похоже, что вы пытаетесь использовать GDC, чтобы избежать блокировки пользовательского интерфейса. Чтобы программно убедиться, что вы не выполняете ресурсоемкие операции в потоке пользовательского интерфейса, и наоборот, вы запускаете обновления графического интерфейса в блоке пользовательского интерфейса, я сделал себе следующие макросы:

/// Stick this in code you want to assert if run on the main UI thread.
#define DONT_BLOCK_UI() \
    NSAssert(![NSThread isMainThread], @"Don't block the UI thread please!")

/// Stick this in code you want to assert if run on a background thread.
#define BLOCK_UI() \
    NSAssert([NSThread isMainThread], @"You aren't running in the UI thread!")

Как видно из комментариев, я склонен использовать эти макросы в начале методов, которые я хочу убедиться, что я не использую по ошибке в неправильном месте. Я поместил эти макросы и другие случайные вещи в https://github.com/gradha/ELHASO-iOS-snippets, которые вы можете найти полезными.

0 голосов
/ 18 октября 2012

Вместо использования // Связки кода, вы должны вставить настоящий код, иначе трудно найти вашу проблему и тратить наше время.Я думаю, вы, вероятно, обновляете пользовательский интерфейс в «связке кода», которая должна быть в основном потоке.

...