I have a global NSMutableArray and I need to update it with values. NSMutableArray is defined in the .h as follows;
#property (strong, nonatomic) NSMutableArray *myDetails;
In the viewDidLoad pre-populate like this;
NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:#"1", #"rowNumber", #"125", #"yards", nil];
NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:#"2", #"rowNumber", #"325", #"yards", nil];
NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:#"3", #"rowNumber", #"525", #"yards", nil];
self.myDetails = [[NSMutableArray alloc] initWithObjects:row1, row2, row3, nil];
Then when the user changes a text field this code is run this;
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSObject *rowData = [self.myDetails objectAtIndex:selectedRow];
NSString *yards = textField.text;
[rowData setValue:yards forKey:#"yards"];
[self.myDetails replaceObjectAtIndex:selectedRow withObject:rowData];
}
When stepping through the code on the line [rowData setValue:yards forKey:#"yards"]; it returns this error;
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
The array is mutable, but what is in it... NSDictionary... is not. You grab an object out of the array...
NSObject *rowData = [self.myDetails objectAtIndex:selectedRow];
and then you try to mutate that object...
[rowData setValue:yards forKey:#"yards"];
The object in the array is the thing you are changing... and it is NSDictionary, immutable, and you can not change it. If you want the dictionary to be mutable, you have to use NSMutableDictionary
Related
I have an NSMutableArray called myMutbaleArray that looks like this when I log it
2015-12-08 17:04:21.679 APP[3342:573379] (
{
id = 19;
"num_test" = 100000;
url = "http://fsad.com";
},
{
id = 20;
"num_test" = 100001;
url = "http://teeeet.com";
}
)
And I want to add an object that looks like this
{
id = 21;
"num" = 100002;
url = "http://example.com";
}
So I am trying this
[myMutbaleArray addObject:#{ #"id":#"23",#"num_test":#"100000", #"url":mainDict[#"website_url"],#"website_name":#"website"}];
But when I do this I get
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
I initialize the array like this
#interface {
NSMutableArray *socailArray;
}
//inside connectionDidFinishLoading
socailArray = [dataDict valueForKey:#"socail"];
Why can I add another dictionary to the MutableArray?
Thanks
If you see this, your array is actually not a mutable array. Here is the hint:
-[__NSCFArray insertObject:atIndex:]
^^^^^^^^^^^
The object is of type __NSCFArray, which is an internal counterpart of NSArray.
Even if you declare your variable as NSMutableArray the pointer can point to an object of any type (event for example NSRegularExpression). Important is, how it is created.
This happens to most people if they serialise an array either using NSUserDefaults, NSJSONSerialization or what ever.
The key is to create a mutable copy when the array gets deserialised using
-[NSArray mutableCopy]
Note that this is not deep-copy. This means an array contained in the root array will not be mutable copied and needs to be replaced separately.
Deep copying can be achieved using this:
// array
NSArray *originalArray = #[#"a", #"b", #[#1, #2]];
NSMutableArray *mutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)originalArray, kCFPropertyListMutableContainers);
// dictionary
NSDictionary *originalDictionary = #{#"a": #"b", #"c": #[#{#"abc": #123}]};
NSMutableDictionary *mutableDictionary = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);
You should change init to:
//inside connectionDidFinishLoading
socailArray = [NSMutableArray arrayWithArray:[dataDict valueForKey:#"socail"]];
Because: [dataDict valueForKey:#"socail"] is a NSArray.
With socailArray = [dataDict valueForKey:#"socail"];, the type of [dataDict valueForKey:#"socail"] is NSArray, so it auto cast socailArray into NSArray, that's why you can not insert thing into this.
To avoid this, you must be hold socailArray as NSMutableArray using:
socailArray = [[dataDict valueForKey:#"socail"] mutableCopy];
Hope this could help.
How to addObject to NSArray using this code? I got this error message when trying to do it.
NSArray *shoppingList = #[#"Eggs", #"Milk"];
NSString *flour = #"Flour";
[shoppingList addObject:flour];
shoppingList += #["Baking Powder"]
Error message
/Users/xxxxx/Documents/iOS/xxxxx/main.m:54:23: No visible #interface for 'NSArray' declares the selector 'addObject:'
addObject works on NSMutableArray, not on NSArray, which is immutable.
If you have control over the array that you create, make shoppingList NSMutableArray:
NSMutableArray *shoppingList = [#[#"Eggs", #"Milk"] mutableCopy];
[shoppingList addObject:flour]; // Works with NSMutableArray
Otherwise, use less efficient
shoppingList = [shoppingList arrayByAddingObject:flour]; // Makes a copy
You can't add objects into NSArray. Use NSMutableArray instead :)
Your array cant be changed because is defined as NSArray which is inmutable (you can't add or remove elements) Convert it to a NSMutableArray using this
NSMutableArray *mutableShoppingList = [NSMutableArray arrayWithArray:shoppingList];
Then you can do
[mutableShoppingList addObject:flour];
NSArray does not have addObject: method, for this you have to use
NSMutableArray. NSMutableArray is used to create dynamic array.
NSArray *shoppingList = #[#"Eggs", #"Milk"];
NSString *flour = #"Flour";
NSMutableArray *mutableShoppingList = [NSMutableArray arrayWithArray: shoppingList];
[mutableShoppingList addObject:flour];
Or
NSMutableArray *shoppingList = [NSMutableArray arrayWithObjects:#"Eggs", #"Milk",nil];
NSString *flour = #"Flour";
[shoppingList addObject:flour];
I have a json parser with AFHTTPRequestOperation.
my parsing code:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
and I have a NSMutableArray
#property (strong, nonatomic) NSMutableArray * myDirectory;
First, I load main 10 items and add with this:
self.myDirectory = responseObject;
After, when I want to load more 10 items, I tried many things but error is:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: '-[__NSCFArray insertObject:atIndex:]:
mutating method sent to immutable object'
I tried:
[self.myDirectory insertObject:[responseObject mutableCopy] atIndex:[self.myDirectory count]];
[self.myDirectory addObjects:responseObject];
etc...
What I must use?
AFNetworking returns immutable arrays (NSArray), so you must assign it like:
self.myDirectory = [responseObject mutableCopy]
did you try [myArray addObjectsFromArray:otherArray];
AFNetworking returns immutable arrays. So try this:
self.myDirectory = [responseObject mutableCopy];
When you want to add the second responseObject to previous self.myDirectory try this:
[self.myDirectory addObjectsFromArray: responseObject];
Check this answer for a clear concept about copy and mutableCopy.
Hope this helps.. :)
EDIT:
NSArray *arr = [[NSArray alloc] initWithObjects:#"A",#"B", nil];
NSArray *arr1 = [[NSArray alloc] initWithObjects:#"C",#"D", nil];
NSArray *arr2 = [[NSArray alloc] initWithObjects:#"E",#"F", nil];
NSMutableArray *mutableArray= [[NSMutableArray alloc] init];
mutableArray = [arr mutableCopy];
[mutableArray addObjectsFromArray:arr1];
[mutableArray addObjectsFromArray:arr2];
NSLog(#"%#",mutableArray);
I am pretty new to objective c and iOS programming, and I have this pretty strange error. The app in question initializes a NSMutableArray with a preset set of values of a custom type I made using NSObject. Which is manipulated by the app. If new values are added during app run time, they are saved using NSUserDefaults, and are brought up from NSUserDefaults along with the default values on next app open.
This is the error I get:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFConstantString 0xb404> valueForUndefinedKey:]: this class is not key value coding-compliant for the key score.'
*** First throw call stack:
(0x1c9b012 0x10d8e7e 0x1d23fb1 0xb84d1d 0xaf100b 0xaf0fbd 0xb0f247 0xb3023c 0xb30056 0x3e40 0x3c5f 0x11f5ad 0x10ec705 0x202c0 0x20258 0x242ff4 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe1056 0x246af9 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe06e8 0x4fcef 0x4ff02 0x2dd4a 0x1f698 0x1bf6df9 0x1bf6ad0 0x1c10bf5 0x1c10962 0x1c41bb6 0x1c40f44 0x1c40e1b 0x1bf57e3 0x1bf5668 0x1cffc 0x290d 0x2835)
libc++abi.dylib: terminate called throwing an exception
I am not quite sure what the error is or how to go about debugging it.
Previously this code worked flawlessly, all I did was remove one or two elements from the preset default list of elements, and in the simulator, simulated deleting the app, and recompiled the code. Ever since my program crashes, with the above message, and I can't figure out how to fix it.
So if someone can give me some help on how to go about debugging this, that would be wonderful. I can attach code as needed, i'm not sure what code would be relevant to be shown, and it may be too much to post all the code involved in the project.
Code to encode and decode the properties of my custom Name NSObject class called name.h:
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeInteger:self.score forKey:#"score"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
if((self = [super init]))
{
self.name = [decoder decodeObjectForKey:#"name"];
self.score = [decoder decodeIntegerForKey:#"score"];
}
return self;
}
Retrieving Data from class, incase this matters, this code occurs in appdelegate.m:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"dataArray"];
NSInteger score = 0;
NSMutableArray *temp = [[NSMutableArray alloc] initWithObjects:#"name", nil];
NSMutableArray *tempList = [[NSMutableArray alloc] init];
for(NSString *y in temp)
{
Name *name = [[Name alloc] init];
name.name = y;
name.score = score;
[tempList addObject:name];
}
if (data)
{
NSArray *list = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSMutableArray *names = [[NSMutableArray alloc]initWithArray:list];
// [_nameList addObjectsFromArray:temp];
NSMutableArray *t = [[names arrayByAddingObjectsFromArray:tempList ] mutableCopy];
_nameList = [[NSMutableArray alloc]init];
[_nameList addObjectsFromArray:t];
}
else
{
//First time load or data is not saved yet
_nameList = [[NSMutableArray alloc] initWithObjects:#"name", nil];
}
saving the array at close time:
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSData *data =[NSKeyedArchiver archivedDataWithRootObject:_nameList];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"dataArray"];
}
same code is in applicationDidEnterBackground.
code to sort by 'score'
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController: (UIViewController *)viewController
{
if(viewController == _viewController3)
{
[self sortNames:_nameList];
[[(ThirdViewController*)_viewController3 topList] reloadData];
}
}
-(void)sortNames:(NSMutableArray*)test
{
NSArray* temp = [[NSArray alloc] initWithArray:test];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"score" ascending:NO];
NSArray *sortedLinks = [[temp sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]] mutableCopy];
_nameList = (NSMutableArray*) sortedLinks;
}
Here's my two cents. You have this line:
[encoder encodeObject:self.name forKey:#"name"];
And then this line:
Name *name = [[Name alloc] init];
This makes me think that the "self.name" property is one of these "Name" custom subclasses.
I believe that if you make a custom subclass and you want it to encodewithcoder, you have to add the encodewithcoder method to your custom subclass and have it encodewithcoder all of its properties and instance variables as primitively as you can.
Meaning, your Name class needs to have its own encodewithcoder method that encodes all of its properties and instance variables that have been stored as factory objects or c primitives.
Edit: I'm still pretty new and value my rep. If I'm wrong, please comment and I'll delete but please don't downvote me to oblivion
Here:
_nameList = [[NSMutableArray alloc] initWithObjects:#"name", nil];
you are adding an NSString to the _nameList array. Later you save that array.
The next time you load that array, you have the NSString #"name" in it. I guess at some point you iterate through the items in _nameList and try to get or set the score, since you are calling this on a subclass of NSString you get the NSUnknownKeyException.
I think what you want to is to replace the line above with something like this: (assuming the class in your name.h file you mentioned above is called Name)
Name *newName = [[Name alloc] init]; //or initialize the way you need to
_nameList = [[NSMutableArray alloc] initWithObjects:newName, nil];
I keep getting this error when i try to bind a nsobject to a segment control
UserLocation isEqualToString:]: unrecognized selector sent to instance 0x7477a60
2013-01-22 12:44:58.115 Momentum[39936:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UserLocation isEqualToString:]: unrecognized selector sent to instance 0x7477a60'
I have verified that my core data object has data.
NSarray *arrayuserlocation = [[MMIStore defaultStore] loadAllUserLocation];
UISegmentedControl *segControl = [[UISegmentedControl alloc]initWithItems:arrayuserlocation];
[segControl addTarget:self action:#selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged];
[segControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[segControl setTintColor:[UIColor grayColor]];
EDIT
To the answer the question below
- (NSMutableArray *)loadAllUserLocation
{
if (!allItems) {NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *e = [[model entitiesByName] objectForKey:#"UserLocation"];
[request setEntity:e]
NSError *error;
NSArray *result = [context executeFetchRequest:request error:&error];
if (!result) {
[NSException raise:#"Fetch failed"
format:#"Reason: %#", [error localizedDescription]];
}
allItems = [[NSMutableArray alloc] initWithArray:result];
}
return allItems;
It returns an array
I was able to solve my problem by doing the following.
NSArray *arraylocation = [[MMIStore defaultStore] loadAllUserLocation];
NSMutableArray *newarray = [[NSMutableArray alloc] init];
for (UserLocation *user in arraylocation)
{
NSLog(#"%# found", user.locationNm);
[newarray addObject:user.locationNm];
}
And using newarray as the datasource for the segment control.
As I mentioned in comments, the issue is that you are passing userlocation objects instead of NSString or UIImage objects required.
As per the documentation your items array should be "an array of NSString objects (for segment titles) or UIImage objects (for segment images)."
You need to fetch the strings from user location as,
NSarray *arrayuserlocation = [[[MMIStore defaultStore] loadAllUserLocation] valueForKey:#"locationNm"];//use the param name here
This should give you an array of all strings from the array of objects.
The problem is, the arrayuserlocation array should contain NSStrings instead of NSManagedObjects.
The code that's throwing the exception is expecting you to pass it an NSString (this is the object that responds to isEqualToString:). However, you are passing it a UserLocation object. You need to load up arrayuserlocation with strings from the UserLocation object, not just send an array of objects themselves.