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

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

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

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

Есть идеи? Выдергивал мои волосы на этом.

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
1 651
5

Ответы 5

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

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

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

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

Я прошел через -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

Сообщали ли вы об этом на bugreport.apple.com, и если да, то каков номер ошибки?

Chris Hanson 04.03.2009 02:34

Я не отправлял ни одного, но отправил сейчас. Идентификатор ошибки №6643022.

Dave Lee 04.03.2009 03:16

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

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

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

--Том

Другие вопросы по теме