- [NSOperationQueue operations]不应该返回一个空数组?

时间:2008-10-30 01:18:30

标签: iphone cocoa multithreading

我正在编写一个将图像异步加载到屏幕上的应用程序。我把它设置为NOT并发(也就是说,它生成一个线程并一次执行一个),所以我只重写了我的NSOperation子类中的[NSOperation main]函数。

无论如何,所以当我添加所有这些操作时,我希望以后能够访问排队的操作来改变它们的优先级。不幸的是,每当我打电话给-[NSOperationQueue operations]时,我所得到的只是一个空数组。最好的部分是,在放入一些控制台打印语句之后,尽管数组为空,但线程仍然在队列中并执行(由打印指示)!

是什么给出的?我还看了一下这个帐户只是为了确保它们都不是一次性执行而且似乎并非如此。

有什么想法吗?把头发拉出来。

编辑:另外值得一提的是,在模拟器中运行时,相同的代码提供了完整的数组:(

5 个答案:

答案 0 :(得分:8)

我走过了-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

答案 1 :(得分:1)

我只是不相信这里有足够的背景来说明发生了什么。显然有些问题是错误的,但你没有说明你是如何限制并发性,你是如何测试以查看对象正在运行等等。

至于模拟器与iPhone,NSOperations在两者之间的行为可能完全不同,因为所有基于Intel的Mac都是多处理器,而且没有iPhone。根据您尝试限制并发性的方式,您可能处于无法在第二个核心上执行的情况下阻止运行等等。但是如果没有更多细节,则无法知道。

答案 2 :(得分:0)

不知道为什么会看到这种行为,但作为一种纯粹的解决方法,您可以在将各个操作添加到队列中时保留对各个操作的引用。

答案 3 :(得分:0)

我在低内存情况下看到了类似的行为。你用了多少内存?当您收到 didReceiveMemoryWarning 消息时,是否正确清除了缓存和其他临时数据?

答案 4 :(得分:0)

我遇到了同样的问题。比我在OS X应用程序上使用的代码更简单,但[myoperationqueue operations]总是返回nil。我打算使用它来避免重复查询。这是在iPhone OS 2.2.1上。当然看起来像个bug。感谢您的代码,我可以使用它,或者只使用我自己的队列镜像。

这不在模拟器上,并且我确认我添加了20个或完全相同的作业副本,这些副本排列很好并且完成了19次太多的工作!

这是非常简单的代码。我几乎没有使用任何内存 - 这是在一个没有ui的应用程序的推出。

- 汤姆