0
votes

I have just started to jump into the realm of iOS. I followed an example in the book and an error is thrown out when I ran it:

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

the example code listed below:

@interface MyXMLElement : NSObject

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *text;
@property (weak, nonatomic) MyXMLElement *parent;
@property (copy, nonatomic) NSMutableArray *children;
@property (copy, nonatomic) NSMutableDictionary *attributes;

@end

============================================

@implementation MyXMLElement

@synthesize name = _name;
@synthesize text = _text;
@synthesize parent = _parent;
@synthesize children = _children;
@synthesize attributes = _attributes;

-(id)init{
    self = [super init];
    if(self != nil){
        NSMutableArray *childrenArray = [[NSMutableArray alloc]init];
        self.children = [childrenArray mutableCopy];
        NSMutableDictionary *attributesDictionary = [[NSMutableDictionary alloc]init];
        self.attributes = [attributesDictionary mutableCopy];
    }
    return self;
}
@end

============================================

@interface MyXMLDocument : NSObject <NSXMLParserDelegate>

@property (nonatomic, strong) NSString *documentPath;
@property (nonatomic, strong) MyXMLElement *rootElement;
@property (nonatomic, strong) NSXMLParser *xmlParser;
@property (nonatomic, strong) MyXMLElement *currentElement;

-(BOOL)parseLocalXMLWithPath:(NSString *)paramLocalXMLPath;
@end    

============================================

@implementation MyXMLDocument

@synthesize documentPath = _documentPath;
@synthesize rootElement = _rootElement;
@synthesize xmlParser = _xmlParser;
@synthesize currentElement = _currentElement;

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if (self.rootElement == nil){
        MyXMLElement *root = [[MyXMLElement alloc] init];
        self.rootElement = root; 
        self.currentElement = root;
    } else {
        MyXMLElement *newElement = [[MyXMLElement alloc] init];
        newElement.parent = self.currentElement;
        [self.currentElement.children addObject:newElement];
        self.currentElement = newElement;
    }
    self.currentElement.name = elementName;
    if ([attributeDict count] > 0){
        //this line will throw out a exception.
        [self.currentElement.attributes addEntriesFromDictionary:attributeDict];
    }
}
1
In wich line the error is thrown?Antonio MG

1 Answers

2
votes
@property (copy, nonatomic) NSMutableDictionary *attributes;

This means that the synthesized method -[MyXMLElement setAttributes:] will make a copy of its argument, using the -copy method. That produces an immutable object, even when the argument is mutable.

Try changing that to:

@property (retain, nonatomic) NSMutableDictionary *attributes;

Also: This code is overcomplicated and leaky.

NSMutableDictionary *attributesDictionary = [[NSMutableDictionary alloc] init];
self.attributes = [attributesDictionary mutableCopy];

Should be:

self.attributes = [NSMutableDictionary dictionary];

What book is this? It's terrible.