@property retain OR copy

3

首先我阅读了这篇文章

我认为我应该在我的程序中使用"copy"。 问题是当我使用NSMutableDictionary时,它会终止。

***** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary removeAllObjects]: mutating method sent to immutable object'**

我不知道什么是"mutating method sent to immutable object"。 我没有将NSDictionary设置为NSMutabledictionary指针。

这是我的代码



.h文件

@interface Button : NSObject {

@private
    NSString*               gID;                                 
    NSString*               gBackColor;                          
    NSString*               gIconImage;                          
    int                     gIndex;                              
    BOOL                    gEnable;                            
    BOOL                    gVisible;
    NSString*               gText;
    
    NSMutableDictionary*    gEvents;
    
    
    BOOL                    gUseCircle;                 
}

@property (nonatomic,copy) NSString                 *ID;
@property (nonatomic,copy) NSString                 *BackColor;
@property (nonatomic,copy) NSString                 *IconImage;
@property int Index;
@property BOOL Enable;
@property BOOL Visible;
@property (nonatomic,copy) NSString                 *Text;
@property (nonatomic,getter=getEvents,retain) NSMutableDictionary       *Events;
@property BOOL UseCircle;

@end

.m 文件

@implementation Button
@synthesize ID = gID;
@synthesize BackColor = gBackColor;
@synthesize IconImage = gIconImage;
@synthesize Index = gIndex;
@synthesize Enable = gEnable;
@synthesize Visible = gVisible;
@synthesize Text = gText;
@synthesize Events = gEvents;
@synthesize UseCircle = gUseCircle;

-(NSMutableDictionary*) getEvents
{
    if (!gEvents) 
    {
        gEvents = [[NSMutableDictionary alloc] initWithCapacity:20];
    }
    return gEvents;
}

- (id) init
{
    self = [super init];
    if (self != nil) 
    {
        gID = @"";
        gBackColor = @"";
        gIconImage = @"";
        gIndex = 0;
        gText = @"";
        
        gUseCircle = NO;
    }
    return self;
}

- (void) dealloc
{
    [gID release];
    [gBackColor release];
    [gIconImage release];
    [gText release];
    
    [gEvents removeAllObjects];
    [gEvents release];
    gEvents = nil;
    
    [super dealloc];
}


And implement

tBtnXML.Events = [self SplitEvents:tNode];

SplitEvents函数:
该函数用于将事件拆分成单个事件,并将其存储在数组中。
-(NSMutableDictionary*) SplitEvents:(NSDictionary*)pEvents
{
    NSMutableDictionary *tEvents = [[NSMutableDictionary alloc] initWithCapacity:5];
    // code blabla
    //.
    //.
    //.
    [tEvents setObject:tEvent forKey:[NSNumber numberWithInt:tEventName]];
    [tEvent release];
            
            

            return [tEvents autorelease];
}

我将 NSMutableDictionary* gEvents 属性从copy更改为retain,代码执行正常。

请问有人能告诉我我的代码有什么问题吗?

如果我的代码在dealloc中出现了错误,请告诉我。

非常感谢您的帮助。

是的,所以我已经修复了我的setter方法:

-(void) setEvents:(NSMutableDictionary*) pEvents
{
    NSMutableDictionary* tNewDict = [pEvents mutableCopy];
    [gEvents removeAllObjects];
    [gEvents release];
    gEvents = tNewDict;
}

这个工作没有出现错误。

它帮助了我很多。

但是我无法投票,>"<~

所以感谢Bavarious :)

1个回答

6
一般情况下,可变属性应该使用retain而不是copy。当你将一个属性声明为copy时,合成的setter方法会向被赋值给该属性的对象发送-copy消息。对于可变对象(例如NSMutableDictionary),向它们发送-copy会创建一个不可变副本,从而有效地创建了一个不可变类型的对象(例如NSDictionary)。因此,在以下代码中:
tBtnXML.Events = [self SplitEvents:tNode];

合成的setter方法会向[self SplitEvents:tNode]发送-copy消息,从而创建该字典的不可变副本(即一个NSDictionary实例),并将其赋值给gEvents。这就是你出错的原因:gEvents被声明为NSMutableDictionary,但实际上指向了一个NSDictionary。
顺便说一下,可变类通常会声明一个-mutableCopy方法来创建可变副本。虽然这个方法不能用于声明属性,但如果你不想使用retain,就需要实现一个自定义的setter方法来使用-mutableCopy。

@wei NSMutableDictionary 实现了 -mutableCopy — 实际上,它符合 NSMutableCopying 协议。问题在于,在 Objective-C 声明属性时综合 setter 方法 不使用 -mutableCopy - user557219
谢谢您的回复 :) NSMutableDictionary 的复制返回一个不可变对象,这是很奇怪的吗? 我想我明白了我的错误。 - wei
好的~~~我明白了~ >"<~~~~ 问题在于,在合成Objective-C声明的属性时,setter方法没有使用-mutableCopy。 - wei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接