从 NSDictionary 中删除一个元素会导致它被过早释放
Removing an element from NSDictionary causes it to be deallocated prematurely
完整的项目可以在这里看到(上下文:https://github.com/atlas-engineer/next-cocoa)
如下代码returnsEXC_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
最后,郑重声明,打开僵尸程序确实可以使代码正常工作,尽管这显然不是解决方案。
您的 window 的 releasedWhenClosed
属性 可能默认为 YES
,这可能与 ARC 的内存管理冲突。创建 window.
时将其设置为 NO
正确答案最终为以下代码序列
- (bool)windowClose:(NSString *)key
{
NSWindow *window = [[self windows] objectForKey:key];
[window setReleasedWhenClosed:NO];
[window close];
[[self windows] removeObjectForKey:key];
return YES;
}
任何其他顺序的事件和对象都会过早释放。
完整的项目可以在这里看到(上下文:https://github.com/atlas-engineer/next-cocoa)
如下代码returnsEXC_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
最后,郑重声明,打开僵尸程序确实可以使代码正常工作,尽管这显然不是解决方案。
您的 window 的 releasedWhenClosed
属性 可能默认为 YES
,这可能与 ARC 的内存管理冲突。创建 window.
NO
正确答案最终为以下代码序列
- (bool)windowClose:(NSString *)key
{
NSWindow *window = [[self windows] objectForKey:key];
[window setReleasedWhenClosed:NO];
[window close];
[[self windows] removeObjectForKey:key];
return YES;
}
任何其他顺序的事件和对象都会过早释放。