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

Оба решения хороши, в зависимости от вашей цели.

Включая память и строку

Делая это, вы не нарушаете код, вы заставляете их использовать C ++ 11 или выше для использования вашей библиотеки. Тем не менее, я считаю это плюсом, так как вам не нужно возиться с множеством ухищрений для поддержки C ++ 98.

При компиляции кода они не должны связываться со стандартной библиотекой, поэтому, если они сделают что-то вроде #defined unique_ptr shared_ptr, я обвиню ваших пользователей в плохом кодировании, а не вас. И да, вы можете попытаться защитить от множества плохих вещей, сделанных пользователями, таких как перегрузка operator& (адрес), однако вы получите код, подобный реализациям STL, который тоже не очень хорош. [ 1114]

Использование pimpl

Использование pimple решает множество проблем, упомянутых выше. Тем не менее, вы не должны использовать его из-за этого. Единственное реальное преимущество pimple - двоичная совместимость.

Поскольку вы не выставляете STL или любые другие библиотеки, кроме своей собственной, вы не должны получать ошибки ссылок на std::string. (Да, это возможно)

Если вы компилируете свою библиотеку с libc++, то std::string на самом деле std::__1::basic_string, std::__1::allocator > с макетом памяти, специфичным для libcxx.

Если вы компилируете свою библиотеку с libstdc++, std::string становится std::basic_string, std::allocator > (или более длинным именем для варианта C ++ 11)

См. этот поток для получения дополнительной информации детали

12
задан Ben Gottlieb 3 November 2008 в 21:40
поделиться

5 ответов

Я ступил через -operations, и найденный, что это в основном делает:

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

кроме, после вызова -autorelease, последующие инструкции перезаписывают регистр, содержащий единственный указатель на новую копию операционной очереди. Вызывающая сторона затем просто получает a 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
8
ответ дан 2 December 2019 в 22:39
поделиться

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

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

1
ответ дан 2 December 2019 в 22:39
поделиться

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

0
ответ дан 2 December 2019 в 22:39
поделиться

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

0
ответ дан 2 December 2019 в 22:39
поделиться

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

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

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

- Том

0
ответ дан 2 December 2019 в 22:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: