I've read all the "unrecognized selector sent to instance" answers, but they don't seem to apply to my situation.
I've setting up a NSMutableDictionary like this...
NSMutableDictionary *ObjectDynamic = [NSDictionary dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil];
and then at some later point in the code I'm trying to add in another object/key, with this...
[ObjectDynamic setObject:mySprite forKey:#"pSObject"];
But I'm getting an exception on that line, with the...
-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance
Is it not possible to add in another key/value pair like that?
Edit
Simple mistake, I just was trying to make a NSDictionary rather than a NSMutableDictionary! Thanks for the answers anyway.
That's because you initialize an immutable NSDictionary that doesn't have a setObject:forKey: method. Initialize a mutable one instead:
NSMutableDictionary *ObjectDynamic = [NSMutableDictionary
dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil];
Since Xcode 4.4 you can also use the new dictionary literals to initialize immutable dictionaries very easily and then use mutableCopy.
NSMutableDictionary *objectDynamic = [#{#"pFObject" : pObject,
#"tFObject" : tObject} mutableCopy];
Note, that in Objective-C you should start variable names with lower case letters.
In order to be able to change the content of a dictionary, you need to make NSMutableDictionary, not an immutable NSDictionary:
NSMutableDictionary *ObjectDynamic = [NSMutableDictionary // <<== Here
dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil
];
Related
Recently I use NSTextTable draw table. I want change some attribute of selected block,so save selected paragraphs into dictionary. After I copy the block of paragraph, once I call method [NSTextTableBlock setBorderColor:], raise an error:
-[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x6000002442c0
I try many times, finally found a phenomenon, which is if I don't copy block, setBorderColor: is OK.
Anyone know relation of [NSTextTableBlock copy] and this error, why [NSTextTableBlock setBorderColor:] cause this error? I'm quite confuse about this error. Thanks in advance.
NSArray does not have the selector replaceObjectAtIndex:withObject: (so you can't call it). You are actually trying to modify an NSArray which can not be modified like that. You probably want NSMutableArray instead. You can create an NSMutableArray from an NSArray, call your method and then replace your reference to the original array like this:
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
[mutableArray replaceObjectAtIndex:index withObject:object];
array = mutableArray;//now the array has been "updated"
Is there a way to create a NSMutableDictionary category that won't crash when assigned a nil value? There is an objectForKeyedSubscript method that we can override for getting the value, but I am not finding the setter version.
I want my dictionary to not crash even when it's assigned nil through subscript.
e.g.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[#"test"] = nil; //won't crash here
I don't know what your use case is but if you are just trying to assign an empty value to a key have you looked at NSNull? If you assign a key in a dictionary to [NSNull null] it will give you most of the benefits of a nil value.
You can use 'setValue:forKey:' to set any value (including nil) in the dictionary
- (void)setValue:(id)value forKey:(NSString *)key
Adds a given key-value pair to the dictionary.
Note that when using key-value coding, the key
must be a string (see “Key-Value Coding Fundamentals”). Discussion
This method adds value and key to the dictionary using
setObject:forKey:, unless value is nil in which case the method
instead attempts to remove key using removeObjectForKey:.
You can’t do this in Objective-C. However, the code you posted does not crash.
I got an exception that says:
-[NSNull objectForKeyedSubscript:]: unrecognized selector sent to instance
Is it saying I am trying to access an NSNull object with a key?
Any idea what causes this and how to fix it or debug further?
The way to fix it is to not attempt objectForKeyedSubscript on an NSNull object. (I'm betting you're handling some JSON data and aren't prepared for a NULL value.)
(And apparently objectForKeyedSubscript is what the new array[x] notation translates into.)
(Note that you can test for NSNull by simply comparing with == to [NSNull null], since there's one and only one NSNull object in the app.)
What ever value you are storing, despite what the editor tells you, at run time you are storing an NSNull, and later on trying to call objectForKeyedSubscript. I am guessing this happening on what is expected to be an NSDictionary. Some thing like:
NSString *str = dict[#"SomeKey"]
Either a piece of code beforehand is not doing its job and investigate there, or perform some validation:
NSDictionary *dict = ...;
if ( [dict isKindOfClass:[NSDictionary class]] ) {
// handle the dictionary
}
else {
// some kind of error, handle appropriately
}
I often have this kind of scenario when dealing with error messages from networking operations.
I suggest adding a category to NSNull to handle this in the same way you would expect a subscript call to be handled if it it were sent to nil.
#implementation NSNull (Additions)
- (NSObject*)objectForKeyedSubscript:(id<NSCopying>)key {
return nil;
}
- (NSObject*)objectAtIndexedSubscript:(NSUInteger)idx {
return nil;
}
#end
A simple way to test is like this:
id n = [NSNull null];
n[#""];
n[0];
With this category, this test should be handled successfully/softly.
- (NSMutableDictionary *)updateTemplates:(NSMutableDictionary *)oldTemplates
forSpecType:(NSString *)specType {
// oldTemplates is an NSMutableDictionary pulled from a plist
// specType is used for flexible paths, to eliminate duplicate code
// Make a dict of the parameters object (about to be overwritten)
NSMutableDictionary *parameters = [oldTemplates valueForKeyPath:
[NSString stringWithFormat:#"root.%#.parameters", specType]];
// Dump the new data into the matching object
[oldTemplates setValue:[updateTemplates valueForKeyPath:
[NSString stringWithFormat:#"data.%#", specType]]
forKeyPath:[NSString stringWithFormat:#"root.%#", specType]];
// Put the parameters back, since they don't exist anymore
/* Instant crash, with the debugger claiming something is immutable
* But I just used the exact same method on the line above
* updateTemplates isn't immutable either; it's only when I try to mutate
oldTemplates after putting in updateTemplates -- and only the update
seems to be breaking things -- that I get the exception and crash
*/
[oldTemplates setValue:parameters forKeyPath:
[NSString stringWithFormat:#"root.%#.parameters", specType]];
return oldTemplates;
}
I could set up a loop to write one object of updateTemplates.specType at a time so only those parts get replaced and then I don't have to do anything with the parameters, but if it's immutable now, it will be when I try to write to it again. That won't do me any good.
If I remember correctly, dictionaries created from plists or NSUserDefaults are immutable by default. You'll have to create a mutable copy manually:
NSMutableDictionary *parameters = [[oldTemplates valueForKeyPath:
[NSString stringWithFormat:#"root.%#.parameters", specType]] mutableCopy];
mutableCopy makes a shallow mutable copy, not a deep mutable copy. If you have an NSDictionary containing key/value pairs where the values are NSDictionary instances, mutableCopy will return a mutable dictionary containing those NSDictionary immutable instances as values.
You either need to do a deep copy or use the plist serialization functionality to decode the plist with the mutable collections option enabled. Or you could compose a new collection derived from the old.
You can simply do:
NSMutableDictionary* oldTemplates = [NSMutableDictionary dictionaryWithDictionary:[oldTemplates valueForKeyPath:
[NSString stringWithFormat:#"root.%#.parameters", specType]]];
This will create a mutable copy from an existing NSDictionary
I have the following data in a NSDictionary Variable:
{
value = "TV-PG";
}
I was wondering how to get the value for key "value" here.
I tried:
NSDictionary *fieldMaturityRating = [[parsedItems objectAtIndex:0] objectForKey:#"field_maturity_rating"];
NSString *dateRelease = [fieldMaturityRating objectForKey:#"value"];
(where, fieldMaturityRating is a NSDictionary with the given value)
and I get:
-[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
[10530:707] *** Terminating app due to uncaught exception: -[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
Can anyone kindly help me ?
Thanks.
Note: if I pause the execution and do a po after the 1st line of code presented here, I get the following:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The po actually shows your issue:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The outer ( and ) mean that your object is actually an array.
Inside that is where the { and } denote your dictionary.
So you really want:
NSString *value = [[fieldMaturityRatingNew objectAtIndex:0] objectForKey:#"value"];
You're actually sending that NSDictionary message to a NSMutableArray instance.
You might want to check your code again as the objectForKey: method is right when pointing to a NSDictionary.
This means your fieldMaturityRating is not actually an NSDictionary. Make sure you aren't setting it to an array somewhere in your code.
Edit:
This means your fieldMaturityRating is actually an NSArray containing an NSDictionary. If this is your intended data structure then you can access your value like so.
NSString *dateRelease = [[fieldMaturityRating objectAtIndex:0] objectForKey:#"value"];
I don't believe this is your intended data structure so you should look into why your parsedItems array returned you an NSArray instead of an NSDictionary. If you track this problem down you can stop any headaches in the future.
Based on your datastructure which is a dictionary inside an array, dateRelease should be like this
NSString *dateRelease = fieldMaturityRating[0][#"value"];