“仅在发布模式下,集合NSArray在被枚举时发生了变异”

时间:2014-12-17 14:27:08

标签: objective-c macos cocoa

我只在发布模式下获得"Collection NSArray was mutated while being enumerated"例外。当我在调试模式下运行应用程序时,一切正常。

如果发布模式下的调试器准确无误,则会在此行代码中崩溃:

- (void)initPersonsTableTableColumnMetadata:(CBEditPersonTableColumnMetadata *)metadata count:(NSInteger)valuesCount
{
    personsTableColumnMetadata = [[NSMutableDictionary alloc] initWithCapacity:valuesCount];
    NSAutoreleasePool *metadataPool = [[NSAutoreleasePool alloc] init];
    for (NSUInteger i = 0; i < valuesCount; i++) {
        CBEditPersonTableColumnMetadata aMetadata = metadata[i];
        NSValue *metadataValue = [NSValue valueWithBytes:&aMetadata objCType:@encode(CBTableColumnMetadata)];
        [personsTableColumnMetadata setObject:metadataValue forKey:aMetadata.columnKey];
    }
    FreeAndNil(metadataPool);
}


-(CBEditPersonTableColumnMetadata)tableColumnMetadataForKey:(NSString *)aKey
{
    CBEditPersonTableColumnMetadata theMetadata;
    NSValue *storedValue = [personsTableColumnMetadata valueForKey:aKey];
    if (storedValue) {
        [storedValue getValue:&theMetadata]; //here
        return theMetadata;
    }
}

- (void)addColumnsToPersonTable:(CBEditableTableView *)table withKeys:(NSArray *)keys andAutosaveName:(NSString*)autosaveName
{
    for (NSString *columnKey in keys) {
        CBEditPersonTableColumnMetadata metadata = [self tableColumnMetadataForKey:columnKey];
        NSTableColumn *newColumn = [[NSTableColumn alloc] initWithIdentifier:columnKey];

        NSCell *cell = nil;

        if ([metadata.columnKey isEqualToString:@"Dragging"]) {
            cell = [[NSImageCell alloc] init];

        } else if ([metadata.editType isEqualToString:[self editableButton]]) {
            cell = [[NSButtonCell alloc] init];
            [cell setAction:@selector(selectAndOpenEditLookup:)];
            [cell setTag:[metadata.editEntity intValue]];
            [cell setImage:[NSImage imageNamed:@"edit-inlist-16x16.png"]];
            [(NSButtonCell*)cell setImageScaling:NSImageScaleProportionallyDown];
            [cell setTarget:self];
            [cell setTitle:@""];

        } else {
            cell = [[CBPaddedTextCell alloc] init];
            if ([metadata.editType isEqualToString:[self notEditableComboBox]]) {
                [cell setEditable:NO];
            }
        }

        [newColumn setResizingMask:NSTableColumnUserResizingMask];
        [[newColumn headerCell] setStringValue:[NSString stringWithFormat:@"  %@",metadata.columnHeader]];

        [[newColumn headerCell] setLineBreakMode:NSLineBreakByTruncatingTail]; // or NSLineBreakByTruncatingMiddle

        if (metadata.minWidth > 0.0) {
            [newColumn setMinWidth:metadata.minWidth];
        }
        if (metadata.maxWidth > 0.0) {
            [newColumn setMaxWidth:metadata.maxWidth];
        }

        [newColumn setWidth:100.0];

        if (![metadata.editType length])
            if ([cell isKindOfClass:[NSTextFieldCell class]])
                [(NSTextFieldCell*)cell setTextColor:[NSColor grayColor]];

        [newColumn setDataCell:cell];
        FreeAndNil(cell);

        if (![metadata.editType isEqualToString:[self editableButton]]) {
            NSDictionary *bindingOptions =  [NSDictionary dictionaryWithObjectsAndKeys:
                                            [NSNumber numberWithBool:NO], NSCreatesSortDescriptorBindingOption,
                                            [NSNumber numberWithBool:YES], NSEditableBinding,
                                            nil];

            [newColumn bind:@"value" toObject:[table arrayController] withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", metadata.bindingKeyPath] options:bindingOptions];
            [[newColumn dataCell] setEditable:YES];
        }

        [newColumn setIdentifier:columnKey];
        [table addTableColumn:newColumn];
        FreeAndNil(newColumn);
    }

    NSTableColumn *newColumn = [[NSTableColumn alloc] initWithIdentifier:@"Remove"];

    NSButtonCell *cell = [[NSButtonCell alloc] init];
    [cell setAction:@selector(removeEditableItem:)];
    [cell setImage:[NSImage imageNamed:@"remove.png"]];
    [cell setImageScaling:NSImageScaleProportionallyDown];
    [cell setTarget:self];
    [cell setTitle:@""];
    [newColumn setMinWidth:20];
    [newColumn setMaxWidth:20];
    [newColumn setWidth:20.0];
    [[newColumn headerCell] setStringValue:@""];

    [newColumn setDataCell:cell];
    FreeAndNil(cell);
    [table addTableColumn:newColumn];
    FreeAndNil(newColumn);

    [table setNeedsDisplay];
    [table reloadData];

    [table setAutosaveName:autosaveName];
    [table setAutosaveTableColumns:YES];
}

- (void)windowDidLoad
{
    [super windowDidLoad];


    NSArray * artistKeys = [NSArray arrayWithObjects:@"Dragging", @"DisplayName", @"FirstName", @"LastName", @"SortName", @"ID", nil];
    [editableArtistTable setArrayController:artistsArrayController];
    [self addColumnsToPersonTable:editableArtistTable withKeys:artistKeys andAutosaveName:@"editableArtistTable"];

CBEditPersonTableColumnMetadata

typedef struct _CBEditPersonTableColumnMetadata {
    NSString *columnKey;
    NSString *columnHeader;
    NSString *bindingKeyPath;
    CGFloat minWidth;
    CGFloat maxWidth;
    NSString *editType;
    NSString *editEntity;
    BOOL     forbidEmpty;
} CBEditPersonTableColumnMetadata;

不确定原因。调试模式一切正常。

更新:控制台日志:

2014-12-17 16:13:20.580 *** Collection <__NSArrayI: 0xf60f0a0> was mutated while being enumerated.
2014-12-17 16:13:20.582 Colr (
    0   CoreFoundation                      0x9711a343 __raiseError + 195
    1   libobjc.A.dylib                     0x98bbda2a objc_exception_throw + 276
    2   CoreFoundation                      0x97119c0a __NSFastEnumerationMutationHandler + 362
    3   Colr                     0x00165e16 -[CBEditItemWithOutletsBase addColumnsToPersonTable:withKeys:andAutosaveName:] + 149
    4   Colr                     0x00192413 -[CBEditItemWithOutlets windowDidLoad] + 343

1 个答案:

答案 0 :(得分:1)

嗯,经过一些调查(你可以看到上面的评论)后发现问题出在initPersonsTableTableColumnMetadata:count:方法

以下行:

NSValue *metadataValue = [NSValue valueWithBytes:&aMetadata objCType:@encode(CBTableColumnMetadata)];  

应该是:

NSValue *metadataValue = [NSValue valueWithBytes:&aMetadata objCType:@encode(CBEditPersonTableColumnMetadata)];  

@encode结构类型不正确 因此,在尝试将其解码回CBEditPersonTableColumnMetadata结构时崩溃了。

我仍然有点疑惑,为什么异常表明它是由于在枚举时改变了数组,但崩溃的方法是从枚举中调用的(尽管它没有影响到数组的对象),修复上面的问题解决了崩溃。