NSDictionary sigbart - ios

i have some very strang behavior in iOS when using a NSMutableDictionary.
I am using the following code to access a dictionary from the app delegate.
self.dictTyp = appDelegate.dictTyp;
NSLog(#"%#", dictTyp);
NSArray *keys = [dictTyp allKeys];
The output of the NSLog is fine and it shows the content of the dictionary. but in the next line when i want to get allKeys i get an failure with unrecognized selector. can anybody tell me what i am doing wrong ?
thanks,
martin

Modify NSLog to print out the type, too:
NSLog(#"%# %#", dictTyp, [dictType class]);
Check if dicType isn't a dictionary but something else. Then go back to where you created it and make sure it is actually created as a dictionary and that it is properly retained and not released too early.

Related

NSMutableArray replaceObjectAtIndex Crash

i use xcode 9
NSMutableArray *Upcase_Keys = #[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"];
NSString *str = [Upcase_Keys objectAtIndex:0];
str = #"test";
[Upcase_Keys replaceObjectAtIndex:0 withObject:str];
Gets specific data for NSMutableArray
It transforms the value and overwrites the existing index.
However, this code causes a crash.
What did I do wrong?
NSMutableArray replaceObjectAtIndex Crash
So there should be an error in console. Console will help you 99% of the cases when there is a crash, read it!
It should be something like -[NSArrayI replaceObjectAtIndex:withObject:] unrecognized selector sent to instance. That's the important part of your error. NSArrayI meaning NSImmutableArray (NSArray in other words), which is not a NSMutableArray which points out that the issue is about the creation of Upcase_Keys.
Why then? Because #[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"]; that's a short hand syntax for NSArray, not NSMutableArray. So even if it's declared as a NSMutableArray, the object is in fact a NSArray.
In fact, if you'd listen to XCode, it should give you this warning:
Incompatible pointer types initializing 'NSMutableArray *' with an
expression of type 'NSArray *'
Which concords with everything said before.` Sometimes XCode may be wrong, but try to listen to it.
There are a few possibilities call:
NSMutableArray *Upcase_Keys = [NSMutableArray arrayWithArray:#[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"]];
NSMutableArray *Upcase_Keys = [[NSMutableArray alloc] initWithArray:#[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"]];
NSMutableArray *Upcase_Keys = [#[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"] mutableCopy];
And finally, a recommendation use camelcase:
Avoid naming your var with an uppercase. Use a lower case for the first letter. I'd say that after the _ is less problematic, but we tend in iOS to write instead.
Upcase_Keys => upcase_Keys => upcaseKeys
You have defined as immutable object, The syntax will assign NSArray reference not NSMutableArray. You can't update the NSArray.
Try like this,
NSMutableArray *Upcase_Keys = [NSMutableArray arrayWithArray:#[#"1",#"2",#"3",#"4,"#"5",#"6",#"7",#"8",#"9",#"0"]];

mutating method sent to immutable object' in nsmutablearray

I want to remove objects from NSmutableArray can one tell me the Best way to remove from NSMutableArray
.h
#property(nonatomic,retain)NSMutableArray *arr_property;
.m
_arr_property=[[NSMutableArray alloc]init];
MTPop *lplv = [[MTPop alloc] initWithTitle:SelectProperty(APP_SHARE.language)
options:[_arr_property valueForKeyPath:#"property_list.property_type_name"]
handler:^(NSInteger anIndex) {
txt_Property.text=[[_arr_property valueForKeyPath:#"property_list.property_type_name"] objectAtIndex:anIndex];
NSLog(#"index number %ld",(long)anIndex);
remove object--->>>
NSLog(#"index number %#",[_arr_property valueForKey:#"property_list"]);
[[_arr_property valueForKeyPath:#"property_list.property_type_name"] removeObjectAtIndex:anIndex]; ////hear the app is crashing
app is crashing error iam getting is
2015-06-09 13:21:31.104 Estater[2170:62264] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'
Think about your code:
_arr_property=[[NSMutableArray alloc]init];
You now have an empty NSMutableArray. It has no elements.
[... removeObjectAtIndex:0];
What did we just say? The array has no elements. It has no element 0 - to have an element 0 it would need to have one element at least, but it doesn't. There is nothing to remove.
[_arr_property valueForKeyPath:#"property_list.property_type_name"]
That part is the weirdest, but let's carry on. When called on an array, valueForKeyPath: results in an NSArray - not an NSMutableArray. So this gives you an empty NSArray. But you cannot say removeObjectAtIndex: to an NSArray, even if it empty - it is not mutable. That's the crash you are experiencing.
The real error is that you are calling removeObject on an element of your NSMutableArray:
[-->[_arr_property valueForKeyPath:#"property_list.property_type_name"]<-- removeObjectAtIndex:0];
The array looks empty, but if filled with something, to remove the first element you should do instead:
[_arr_property removeObjectAtIndex:0];
Firstly, you cannot work with NSMutableArray for key value coding it does not support. You must better use NSMutableDictionary for it.
As dictionaries store objects based on a key, whereas arrays store objects based on an index.
You can use NSMutableDictionary like this:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:something forKey:#"Some Key"];
// ... and later ...
id something = [dict objectForKey:#"Some Key"];
Secondly, valueForKeyPath: returns a value not array and valueForKey: returns array of value for the key and also that array is not mutable.
Edit:
Thirdly, after researching more on valueForKeyPath:, found its use in collection operation and syntax for using is. So, do it by changing
[_arr_property valueForKeyPath:#"property_list.property_type_name"]
To
[_arr_property valueForKeyPath:#"#property_list.property_type_name"]

Changing NSNumber nested in NSMutableDictionary and NSMutableArray

I'm not to be able to change a NSNumber within a NSMutableDictionary. The 'Before' NSLog prints but then crashes when I change the number.
As you can see the class is of type NSNumber and therefore I should be able to change the number with the class method 'numberWithIn'. However, I get the error "unrecognized selector sent to instance." Which is strange because if the method didn't exist, the if statement would not work? Thoughts? Have I just missed something strange?
Data is an NSMutableArray and within are NSMutableDictionaries from json data. Data has been initialised.
if([[Data[i] objectForKey:#"Pop"] isKindOfClass:[NSNumber class]]){
NSLog(#"Before: %#",[Data[i] objectForKey:#"Pop"]);
[[Data[i] objectForKey:#"Pop"] numberWithInt:5];
NSLog(#"After: %#",[Data[i] objectForKey:#"Pop"]);
}
if([[Data[i] objectForKey:#"Pop"] isKindOfClass:[NSNumber class]]){
NSLog(#"Before: %#",[Data[i] objectForKey:#"Pop"]);
[[Data[i] setObject:[NSNumber numberWithInt:5] forKey:#"Pop"];
NSLog(#"After: %#",[Data[i] objectForKey:#"Pop"]);
}
should work.
You didnt properly set a new NSNumber object.
[Data[i] objectForKey:#"Pop"] just access an element of your dictionary. If you want to change it you need a method that does so: [Data[i] setObject:[NSNumber numberWithInt:5] forKey:#"Pop] or more concisely [Data[i] setObject:#5 forKey:#"Pop"]. Did you know you can also access dictionary elements now like so: Data[i][#"Pop"]...
+(NSNumber *)numberWithInt:(int)value is a class method to create a new NSNumber. You cannot call it on an instance of NSNumber.
You should use one of those function :
[dataArray setObject:yourObject forKey:#"Pop"];
[dataArray replaceObjectAtIndex:theIndextoChange withObject:yourObject];

How does this NSMutableArray alloc&init work?

I see a new kind of alloc&init NSMutableArray way in one project. It's like this A
NSMutableArray *array = [#[] mutableCopy]; and this works well, and i want to try whether its possible to use BNSMutableArray *array = [NSMutableArray mutableCopy]; it build succeeded, but got this error when used: +[NSMutableArray addObject:]: unrecognized selector sent to class 0x38bedc2c
Now i want to know how does A work? and why B is wrong? A is better than normal alloc&init?
Any help will be appreciated.
mutableCopy is an instance method declared in NSObject class. It is called on any instance to create a mutable copy of it.
In first case #[] will create an autoreleased NSArray instance on which calling mutableCopy will create NSMutableArray instance.
In second case calling mutableCopy on the class is incorrect because it is not meant to be called that way. This will get compiled but will cause exception at runtime.
Hope that helps!
In the first case, you're first initializing an empty NSArray instance; think of #[] as equivalent to [[NSArray alloc] init]. Therefore you're sending mutableCopy to a correct instance, so it works fine.
In the second case, you're sending the message to a class (as opposed to an instance of it), which doesn't make much sense, because the addObject message can only be sent to an instance, not the class itself.
#[] means an NSArray with no object. It returns an NSArray, and then its mutableCopy is copied to array.
+[NSMutableArray addObject:] is invalid as addObject is an instance method and you are trying to use it as class method.
Even NSMutableArray *array = [NSMutableArray mutableCopy]; is incorrect!!! As nothing is created, it is not been allocated and inited. If you log the array, it will only print the string NSMutableArray. Also you can't use array to addObject and other operations.
You should use NSMutableArray *array = [NSMutableArray array];
The first one is lazy typing.
You should avoid it.
It creates an empty NSArray from the array literal syntax and the creates a mutable copy.
That's saving a little typing by creating an unnecessary array.
You should just use
[NSMutableArray new]
Or
[[NSMutableArray alloc] init]
Or if possible because you know the initial capacity in advance
[[NSMutableArray alloc] initWithCapacity:someNSUIntegerValue]
Anything else above is laziness.
Only use mutableCopy when you are actually copying some content.

Why am I getting "[__NSArrayI allKeys]: unrecognized selector sent to instance" / why is NSDictionary transforming?

Looking this [__NSArrayI allKeys]: unrecognized selector sent to instance error up, it seemingly occurs when you send an NSArray the allKeys message which is meant for NSDictionary, but in this case I'm very clearly sending it to an NSDictionary.
Here's the code I use when interfacing with the Pocket API:
NSDictionary *articles = [response objectForKey:#"list"];
// Create an array we can use to sort the keys (and thus the articles) in order of when they were added
NSMutableArray *allKeys = [[articles allKeys] mutableCopy];
The last line there causes the error. But articles is very clearly declared as an NSDictionary? Why is it not liking it?
Oddly enough, if I inspect it at runtime it says it's an NSArray! Why did it change?
(lldb) po articles
$5 = 0x082103e0 <__NSArrayI 0x82103e0>(
)
(lldb) po [articles class]
$6 = 0x01b83b8c __NSArrayI
(lldb)
It may be declared in your code as a dictionary, but that doesn't make it a dictionary. It is truly an array and that is why you get the exception. Check your response so you know what you should expect.
Your code compiles because the compiler doesn't know that it's going to be an array and it trusts you that it will be a dictionary. It does this because objectForKey: returns id.

Resources