addObject replaces all the previous objects in NSMutableArray - objective-c

In my IOS app, I have two view controllers. ControllerA and ControllerB. I have an array of objects in ControllerA. ControllerB creates a new Object and adds it to the array in ControllerA. I do this with a reference to the array and pass that to ControllerB. I add a new object in ControllerB, but when I move back to ControllerA, the array has the right size, but all of the contents are the same.
The array is of type Group.
What do you think the issue is?
Code that adds object in controllerB:
NSString *groupName = userName.text; //gets value from UITextField
NSString *pword = password.text;
Group *newgroup = [[Group alloc]init:groupName :pword]; //init values are just NSString's in a class called Group
[groups addObject:newgroup];
[ViewController print];
[self dismissModalViewControllerAnimated:YES];

Related

In Objective-C, How to initialize NSMutableArray with objects in another NSMutableArray using tableView reference

Developing for MacOS, I have an NSMutableArray namesArray[] that contains 3 String objects.
namesArray[] is represented in a tableView, where user can select multiple cells, each cell represents a single object.
I am trying to initialize a second NSMutableArray savedNamesArray[], and add objects from the original namesArray[] based on the selected cells in my tableView using this method:
NSMutableArray *savedNamesArray = [[NSMutableArray alloc] initWithObjects:[namesArray objectsAtIndexes:[_tableView selectedRowIndexes]], nil];
The problem is, no matter how many objects I select, only one gets added to the new NSMutableArray. Any suggestions?
You're adding one object, an array, to savedNamesArray. Use initWithArray: instead.
NSMutableArray *savedNamesArray = [[NSMutableArray alloc] initWithArray:[namesArray objectsAtIndexes:[_tableView selectedRowIndexes]]];

Editing a local instance of a object changes the object in its main array

In my app I created a bunch of object classes for data that I save in NSUserDefaults.
I get the item by:
LauncherToDoItem *item = [[ActionHelper sharedInstance] actionList][indexPath.row];
then i pass it on to a editing view controller:
LauncherEditActionViewController *editActions = [[LauncherEditActionViewController alloc] initWithToDoItem:item];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:editActions];
[self presentViewController:navController animated:YES completion:nil];
In the view controller I have a table that shows data from a editing version of the item.
- (id)initWithToDoItem:(LauncherToDoItem *)toDoItem {
self=[super initWithStyle:UITableViewStyleGrouped];
if (self) {
item = toDoItem;
editedToDoItem = toDoItem;
}
return self;
}
When I edit the editedToDoItem it also writes the the item, so I assume it's also writing to the version in the array? Why is it that by editing 1 of them affect it all? I dont save it back to the array yet but values save automatically.
That's because both item and editedToDoItem point to the same object — and the same exact location in memory. When you write item = toDoItem, what you're really doing is saving the pointer to toDoItem inside the variable item. It's a reference to the original object, not a copy, because Objective-C object variables are pointers to the objects in memory.
Consider the following code:
NSMutableString *string = [#"Hello, world!" mutableCopy];
NSMutableString *a = string;
NSMutableString *b = string;
// string, a, and b point to the same exact object.
[string appendString:#" Hi again!"];
NSLog(#"%#", a); // => "Hello, world! Hi again!"
[b appendString:#" Whoa!"];
NSLog(#"%#", a); // => "Hello, world! Hi again! Whoa!"
When you fetch the item from your array, then store it twice in the editing controller, you're just passing around references to the same object, which, when edited, will reflect on all other references that you have — because they point to the same location in memory.
If you really want several different copies of the object (so that editing one doesn't affect the others), you have to actually copy the objects by making them conform to the NSCopying Protocol and using [item copy].

IOS: fill a NSMutableArray with some NSMutableArray

In my project I must fill an NSMutableArray with some NSMutable array, my code is:
This is a method
-(void) fill {
[smallArray removeAllObjects]; //when I call this method I delete every object inside smallArray
for {
//in this for I fill with some object a NSMutableArray that I called "smallArray"
[smallArray addObject:object];
}
//outside this for I have my NSMutable bigArray that I must fill with smallArray
[bigArray = ?????];
How can I fill this bigArray?
Unlesss I'm missing something, simply use the addObject: method (as you're already doing for the small array), supplying the smallArray to add.
i.e.: [bigArray addObject:smallArray];
If however you just want to add the objects from smallArray into the bigArray, then you could use the addObjectsFromArray: method...
[bigArray addObjectsFromArray:smallArray];
...which will append the objects after any existing ones within bigArray. For more information, check out the relevant section of the NSMutableArray Class Reference documentation.
If i understang correctly you must have an array that contains other arrays?
[bigArray addObject:smallArray];
Then you can access the array like this
NSMutableArray * arrayfromArray =[bigArray objectAtIndex: someIndex];

Obj-c: returning NSArray from method - objects out of scope

My question is very similar to this question but with a few differences.
I have a class that takes in XML int the form of an NSString, parses out some objects and returns them in an NSArray somewhat like this:
//Parser.m
+(NSArray *)parseMessagesFromXml:(NSString *)xml
{
NSMutableArray *messages = [[NSMutableArray alloc] init];
//do some work parsing the xml
//for each <row>
// Message *m = makeMessageFromRow(row);
return [messages autorelease];
}
Then in my view controller class I declare an NSArray:
//MyViewController.h
NSArray *messages;
#property (nonatomic, retain) NSArray *messages;
and assign it using the above method:
//MyViewController.m
messages = [Parser parseMessageFromXml:xml];
[[self tableView] reloadData];
So here comes the problem: when i assign the array to messages it has elements in it, but they are all "out of scope." I have debugged the problem and I know that the parsing method is correctly creating the objects and adding them to the NSMutableArray before returning it. When I try to access the objects in messages my app crashes and the debugger says EXC_BAD_ACCESS. What is more peculiar is this: if i store the array into a local variable it works just fine:
NSArray *temp = [Parser parseMessageFromXml:xml];
//temp has all the right objects and they are in scope
messages = temp;
//messages has the objects, but cannot access them (they are out of scope).
It is as if I can legally view them in a local scope, but i cannot assign them to a member variable. I have even tried iterating over the returned array, adding each one to messages individually, but the result is the same: they are out of scope. I am totally clueless on this one.
What is it about messages as a member variable that doesn't allow it to hold these objects?
The problem is that the array is being released. When you call autorelease in parseMessagesFromXml:, you tell the array that it should be released sometime in the future. This is happening before the table reloads its data. You need to retain the array again to prevent it from being released. In this case, it is as simple as using the accessor methods to set your property instead of setting the instance variable directly.
//MyViewController.m
self.messages = [Parser parseMessageFromXml:xml];
[[self tableView] reloadData];

Issues declaring already existing NSMutableArray in new class

I have a class (DataImporter) which has the code to download an RSS feed. I also have a view and separate class (TableView) which displays the data in a UITableView and starts the parsing process, storing parsed information in an NSMutableArray (items) which is located in the (TableView) subclass.
Now I wish to add a UIMapView which displays the items in the (items) NSMutableArray. Herein lies the issue - I need to somehow get the data from the (items) NSMutableArray into the new (mapView) subclass which I'm struggling with - and I preferably don't want to have to create a new class to download the data again for the mapView class when it already is in the applications memory. Is there a way I can transfer the information from the NSMutableArray (items) class to the (mapView) class (i.e. how do I declare the NSMutableArray in the (mapView) class)?
Here's a overview of how the system works:
App opened> Data downloaded (using DataImporter class) when (TableView) viewDidLoad runs> Data stored in NSMutableArray accessible by the (TableView) class> And from here I need to access and declare the array from a new (mapView) class.
Any help greatly appreciated, thanks.
Code for viewDidLoad MapKit:
Data *data = nil;
NSString *ilocation = [data locations];
NSString *ilocation2 = #"New Zealand";
NSString *inewlString;
inewlString = [ilocation stringByAppendingString:ilocation2];
NSLog(#"inewlString=%#",inewlString);
if(forwardGeocoder == nil)
{
forwardGeocoder = [[BSForwardGeocoder alloc] initWithDelegate:self];
}
// Forward geocode!
[forwardGeocoder findLocation: inewlString];
Code for parsing data into original NSMutable Array:
- (void)beginParsing {
NSLog(#"Parsing has begun");
//self.navigationItem.rightBarButtonItem.enabled = NO;
// Allocate the array for song storage, or empty the results of previous parses
if (incidents == nil) {
NSLog(#"Grabbing array");
self.datas = [NSMutableArray array];
} else {
[datas removeAllObjects];
[self.tableView reloadData];
}
// Create the parser, set its delegate, and start it.
self.parser = [[DataImporter alloc] init];
parser.delegate = self;
[parser start];
}
Since you have a property self.datas you can get a reference to the data just by calling that from your UIMapView, or by assigning to some target property in your map view from whatever object controls both views:
mapView.someArrayProperty = tableView.datas
However, you might want to rethink your overall program structure. Keeping what is in effect model data inside views is not good practice and tends make things pretty spaghetti-like as you add more objects and functionality.