Удаление элемента из NSDictionary приводит к его преждевременному освобождению - PullRequest
0 голосов
/ 23 сентября 2018

Полный проект можно посмотреть здесь (для контекста: https://github.com/atlas-engineer/next-cocoa)

Следующий код возвращает EXC_BAD_ACCESS:

- (bool)windowClose:(NSString *)key
{
    NSWindow *window = [[self windows] objectForKey:key];
    [[self windows] removeObjectForKey:key];
    [window close];
    return YES;
}

Однако следующий код работает

- (bool)windowClose:(NSString *)key
{
    [[self windows] removeObjectForKey:key];
    return YES;
}

Как и следующее:

- (bool)windowClose:(NSString *)key
{
    NSWindow *window = [[self windows] objectForKey:key];
    [window close];
    return YES;
}

Только когда вы их соединяете, все ломается.

Для справки, я предоставил реализацию AutokeyDictionary ниже, котораязначение [self windows] в приведенных выше примерах

//
//  AutokeyDictionary.m
//  next-cocoa
//
//  Created by John Mercouris on 3/14/18.
//  Copyright © 2018 Next. All rights reserved.
//

#import "AutokeyDictionary.h"

@implementation AutokeyDictionary
@synthesize elementCount;

- (instancetype) init
{
    self = [super init];
    if (self)
    {
        [self setElementCount:0];
        _dict = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (NSString *) insertElement:(NSObject *) object
{
    NSString *elementKey = [@([self elementCount]) stringValue];
    [_dict setValue:object forKey: elementKey];
    [self setElementCount:[self elementCount] + 1];
    return elementKey;
}

- (NSUInteger)count {
    return [_dict count];
}

- (id)objectForKey:(id)aKey {
    return [_dict objectForKey:aKey];
}

- (void)removeObjectForKey:(id)aKey {
    return [_dict removeObjectForKey:aKey];
}

- (NSEnumerator *)keyEnumerator {
    return [_dict keyEnumerator];
}

- (NSArray*)allKeys {
    return [_dict allKeys];
}

@end

Наконец, для записи, включение зомби делает код работающим, хотя это, очевидно, не является решением.

Ответы [ 2 ]

0 голосов
/ 23 сентября 2018

Правильный ответ в итоге был следующей последовательностью кода

- (bool)windowClose:(NSString *)key
{
    NSWindow *window = [[self windows] objectForKey:key];
    [window setReleasedWhenClosed:NO];
    [window close];
    [[self windows] removeObjectForKey:key];
    return YES;
}

любого другого порядка событий, и объект был бы преждевременно освобожден.

0 голосов
/ 23 сентября 2018

Свойство releasedWhenClosed вашего окна, вероятно, имеет значение по умолчанию YES, что может конфликтовать с управлением памятью ARC.При создании окна установите значение NO.

...