2015-02-18 1 views
8

Эта строка кода вызывается в моем методе awakeFromFetch, расположенном внутри настраиваемого управляемого объекта, который реализует NSManagedObject. Эта строка, в частности, вызывает звонок в мой однопользовательский сетевой менеджер, называемый sharedManager.Отправка один раз (dispatch_once) singleton freezes/locks в объекте c

[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ]; 

Блок dispatch_once будет удален, как показано ниже. Обратите внимание на то, что она реализуется в хорошем смысле, как это показано here:

enter image description here

Вызов dispatch_once затем переходит к once.h и здесь она замерзает прямо на выделенной линии:

dipatch_once deeper

Вот трассировки стека:

stack trace

Все это происходит при попытке загрузить ранее сохраненный файл сетевой очереди. Приложение полностью закрывается для сохранения, а затем запускается снова, а затем происходит это замораживание/блокировка.

Я даже попытался использовать этот код вместо этого, чтобы решить проблему, как предлагается here, и это не сработало. Но изменение этого, вероятно, не имеет значения, так как мой оригинальный код dispatch_once работает очень хорошо в течение длительного времени. Это только в этом конкретном случае.

if ([NSThread isMainThread]) 
{ 
    dispatch_once(&onceToken, ^{ 
    stack = [[KACoreDataStack alloc] init];}); 
} 
else 
{ 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
    dispatch_once(&onceToken, ^{ 
    stack = [[KACoreDataStack alloc] init];}); 
}); 
} 

До сих пор, это мои источники для устранения неполадок такого рода проблемы:

Благодарим за помощь!

ответ

0

Благодаря помощи alexcurylo, в порядке очередности loadFromDisk, проблема была решена. Для того, чтобы люди не путались, так получилось, что с этим кодом ниже я выполняю очередь с заданием, которое загружает массив (который действует как сохраненная очередь пользовательских запросов) с диска. Вы могли бы быть в очереди за любую работу, например, загрузка изображений/и т.д. Следующий код в моем классе sharedManager (где нагрузка с диска вызывается) работает, как показано здесь:

-(void) loadQueueFromFileByQueueing 
{ 
    //Create a Queue 
    /* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/ 
    fileStrQueue = [[NSOperationQueue alloc] init]; 

    //Create an operation which will invoke method loadQueueFromDisk 
    NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil]; 

    //Add this operation to the queue 
    [fileStrQueue addOperation:operation]; 

    //Releasing the above operation as it is already retained by the queue. 
    // [operation release]; // If you are using ARC, this won't be necessary 
} 
6

Черт сын, это одно замечательное задание на вопрос.

Проблема в том, что рекурсивные вызовы dispatch_once будут взаимоблокировками. Если вам нужны точные данные, you can find them with the source here. Поэтому вам нужно переписать, чтобы этого избежать.

Мое мнение, что существует архитектурная ошибка, связанная с тем, что ведет к этому звонку -loadQueueFromDisk. Вы абсолютно не делаете не хотите делать что-либо, что потенциально неограниченно во время выполнения, как выходить и загружать что-то с диска внутри dispatch_once. То, что вы хотите делать, - это абсолютный минимум для создания адресного синглтона и возврата. Затем дайте ему внутреннее состояние «Инициализация» и отправьте материал для загрузки диска в неблокирующую очередь где-нибудь.Таким образом, все, что не зависит от загружаемого с диска материала, может продолжаться, и все, что зависит от загружаемого с диска материала, может добавить себя в очередь загрузки диска или проверить каждые несколько сотен миллисекунд, чтобы увидеть если он еще находится в «Инициализированном» состоянии или что-то в этом роде.

+0

Спасибо! Я думаю, вы, конечно, что-то о архитектуре. Вся эта загрузка с диска добавляется после того, как приложение было заархивировано и, очевидно, оно не играет с ним хорошо. WKNetworkManager (sharedManager) вызывает '[self loadQueueFromDisk];'. Поэтому, в свою очередь, создавая декодированные объекты, эти инициализации объектов инициируют вызовы sharedManager. Это может быть проблематично. Связанное решение выглядит громоздким. Как вы думаете, будет ли выполняться блок-оператор loadQueueFromDisk для делегирования задачи другому потоку? – Marcel

+0

Если вам понравился вопрос, повысьте его! – Raspu

+1

Ну, основные данные и потоки, которые могут быстро усложниться. Мой первый наклон для инициализации Core Data с удалением диска, как это, заключается в том, чтобы бросить его в очередь с низким приоритетом GCD 'dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_LOW, 0),^{[self loadQueueFromDisk];});' поэтому он получает очереди с высоким и нормальным приоритетом пустые. Поскольку это, скорее всего, будет желательным поведением при запуске. –

Смежные вопросы