iOS, NSMutableDictionary
Asked Answered
R

3

8

I had a problem in my project where I declared in the header file an NSMutableDictionary property like so:

@property (copy, nonatomic) NSMutableDictionary *DataDict ;

Now in the implementation file, I go ahead and initialise this dictionary because I am gonna use it, like so:

DataDict = [[NSMutableDictionary alloc]init];

Now when I did this, the minute I try to add something to this dictionary I would get this error message:

-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x885ae60 2012-10-19 16:51:56.040 testing[2297:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x885ae60'

After a while and running through my project a thousand times, I decided to uncomment my initialization line, like so

 //DataDict = [[NSMutableDictionary alloc]init];

and that fixed the problem.

My question is: Why?

Ragin answered 19/10, 2012 at 20:55 Comment(0)
S
15

The problem is in the way you have defined your property. If you change it to:

@property (strong, nonatomic) NSMutableDictionary *DataDict ;

instead of copy everything should be fine.

This happens because you basically say that you want a copy of your object through your generated accessors, which returns an NSDictionary instead (an immutable copy).

You can find more on objective-c properties here.

Just as a sidenote: objective-c ivars usually start with a lowercase letter (uppercase names are used for classes), so dataDict should be preferred over DataDict.

Spoonfeed answered 19/10, 2012 at 21:8 Comment(2)
Does that mean I should make the reference strong, and then alloc init? or make it strong and no need to alloc init?Ragin
By making it strong you just saying that you want to keep a strong relationship (owning) with that object (which basically means that you want it to be deallocated when the owner deallocates). You still have to alloc/init the object as always.Spoonfeed
R
2

It is because the property have "copy" attribute so NSMutableDictionary instance alloc/init-ed is "copy"'ed using "copy" method, and "copy" method create not NSMutableDictionary but NSDictionary. ("mutableCopy" will create NSMutableDictionary).

Probably, you can use "retain" instead of "copy" as attributes.

@property (retain, nonatomic) NSMutableDictionary *DataDict ;

Or, just without "copy"/"retain" but use ARC.(Automatic reference counting).

Radiancy answered 19/10, 2012 at 21:7 Comment(0)
R
0

I have this exact problem. No combination of retain/copy/strong/weak, etc do the trick. What does work is to create a temporary Mutable Dictionary, load it up and then set my original equal to it.

 NSMutableDictionary * tempD = [[NSMutableDictionary alloc] init];

[tempD setObject: epsTapeCut forKey:LWPrintParameterKeyTapeCut];
[tempD setObject: epsCopies forKey:LWPrintParameterKeyCopies];
[tempD setObject: epsHalfCut forKey:LWPrintParameterKeyHalfCut];
[tempD setObject: epsPrintSpeed forKey:LWPrintParameterKeyPrintSpeed];
[tempD setObject: epsDensity forKey:LWPrintParameterKeyTapeWidth];

self.ePSprintSettings = tempD;

This fails:

 [self.ePSprintSettings setObject: epsTapeCut forKey:LWPrintParameterKeyTapeCut];

Declaration:

 @property (nonatomic, retain) NSMutableDictionary *ePSprintSettings;

(But again, no combination of attributes makes a difference.)

Initialization:

 self.ePSprintSettings = (NSMutableDictionary *)[myUserDefaults dictionaryForKey:kEpsPrintSettings];

Thank you for helping me understand.

I'm happy enough that this works, but I'd like to understand why.

Renettarenew answered 3/12, 2020 at 1:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.