Подтвердить что ты не робот

- [NSOperationQueue операции] возвращает пустой массив, когда он не должен?

Я пишу приложение, которое выполняет асинхронную загрузку изображений на экран. Я настроил его не одновременно (то есть, он порождает поток и выполняет их по одному), поэтому я только переопределил функцию [NSOperation main] в моем подклассе NSOperation.

В любом случае, поэтому, когда я добавляю все эти операции, я хочу, чтобы позже мог получить доступ к операциям в очереди, чтобы изменить их приоритеты. К сожалению, всякий раз, когда я называю -[NSOperationQueue operations], все, что я возвращаю, это пустой массив. Самое приятное то, что после ввода некоторых консольных операторов печати потоки все еще находятся в очереди и выполняются (обозначены отпечатками), несмотря на то, что массив пуст!

Что дает? Я также посмотрел на этот счет, чтобы убедиться, что все они не выполняются сразу, и это, похоже, не так.

Любые идеи? Вытягивая мои волосы на этом.

EDIT: Также стоит упомянуть, что тот же код предоставляет полный массив при запуске в симуляторе: (

4b9b3361

Ответ 1

Я прошел через -operations и обнаружил, что он в основном выполняет:

[self->data->lock lock];
NSString* copy = [[self->data->operations copy] autorelease];
[self->data->lock unlock];
return copy;

кроме, после вызова -autorelease последующие инструкции перезаписывают регистр, содержащий единственный указатель на новую копию очереди операций. Затем вызывающий абонент получает возвращаемое значение nil. Поле "data" является экземпляром внутреннего класса с именем _NSOperationQueueData, который имеет поля:

NSRecursiveLock* lock;
NSArray* operations;

Мое решение заключалось в подклассе и переопределении -operations, следуя той же логике, но фактически возвращающей копию массива. Я добавил некоторые проверки работоспособности, чтобы помочь, если внутренние элементы NSOperationQueue не совместимы с этим исправлением. Эта повторная реализация вызывается только в том случае, если вызов [super operations] действительно возвращает nil.

Это может сломаться в будущих выпусках ОС, если Apple изменит внутреннюю структуру, но каким-то образом избежать фактической фиксации этой ошибки.

#if TARGET_OS_IPHONE

#import <objc/runtime.h>

@interface _DLOperationQueueData : NSObject {
@public
    id lock; // <NSLocking>
    NSArray* operations;
}
@end
@implementation _DLOperationQueueData; @end

@interface _DLOperationQueueFix : NSObject {
@public
    _DLOperationQueueData* data;
}
@end
@implementation _DLOperationQueueFix; @end

#endif


@implementation DLOperationQueue

#if TARGET_OS_IPHONE

-(NSArray*) operations
{
    NSArray* operations = [super operations];
    if (operations != nil) {
        return operations;
    }

    _DLOperationQueueFix* fix = (_DLOperationQueueFix*) self;
    _DLOperationQueueData* data = fix->data;

    if (strcmp(class_getName([data class]), "_NSOperationQueueData") != 0) {
        // this hack knows only the structure of _NSOperationQueueData
        // anything else, bail
        return operations;
    }
    if ([data->lock conformsToProtocol: @protocol(NSLocking)] == NO) {
        return operations; // not a lock, bail
    }

    [data->lock lock];
    operations = [[data->operations copy] autorelease];
    [data->lock unlock];
    return operations; // you forgot something, Apple.
}

#endif

@end

Файл заголовка:

@interface DLOperationQueue : NSOperationQueue {}
#if TARGET_OS_IPHONE
-(NSArray*) operations;
#endif
@end

Ответ 2

Я просто не верю, что здесь достаточно контекста, чтобы сказать, что происходит. Очевидно, что-то не так, но вы не говорите, как вы ограничиваете concurrency, как вы тестируете, чтобы увидеть, что объекты запущены и т.д.

Что касается симулятора и iPhone, то NSOperations может действовать совершенно по-разному между этими двумя, поскольку все Mac на базе Intel являются многопроцессорными, и никаких iPhone не существует. В зависимости от того, как вы пытаетесь ограничить concurrency, вы можете оказаться в ситуации, когда невозможно выполнить выполнение на втором ядре, запрещает запуск файлов и т.д. Но без каких-либо подробностей это невозможно узнать.

Ответ 3

Не знаю, почему вы видите это поведение, но в качестве обходного пути вы можете сохранить свои собственные ссылки на отдельные операции, поскольку они добавлены в очередь.

Ответ 4

Я видел подобное поведение в ситуациях с низкой памятью. Сколько памяти вы используете? Вы правильно очищаете кеши и другие временные данные, когда получаете сообщение didReceiveMemoryWarning?

Ответ 5

Я столкнулся с одной и той же проблемой. Простой код, чем я использую в приложении OS X, и все же [операции myoperationqueue] всегда возвращает nil. Я планировал использовать это, чтобы избежать дублирования запросов. Это на iPhone OS 2.2.1. Конечно, похоже на ошибку. Спасибо за код, я могу использовать его или просто использовать собственное зеркало очереди.

Это не на симуляторе, и я подтверждаю, что добавляю 20 или точные копии задания, которые все выстраиваются красиво и делают работу в 19 раз слишком много!

Это действительно довольно простой код. Я почти не использую память - это при запуске приложения, которое пока не имеет ui.

- Том