How to stop reallocation of an NSArray in iPhone? - iphone

I am using an NSArray and alloc it to in viewDidload method.
I have two views in my app and add data to this array from these views. The total number of rows shown in a table according to [array count].
But the problem I'm facing is that when I call the view where I'm using this array from another view then this array realloc and due to this my array size again start from 0. I don't want that. I want the array size start from its last position.
So please help me to remove out this problem where I declare this array or any alternate to do this.

You need to make the array lazily loaded.
Have the view where the array is located have a getter that looks like this:
-(NSArray *)theArray {
if(theArray == nil) {
theArray = [[[NSArray alloc] init] autorelease]; //If using ARC, don't autorelease
}
return theArray;
}
In your firstView's viewDidLoad, just call the array like this:
[self theArray];
Now in your second view, call the first array like this
[firstView theArray];

Related

Display JSON as List in ViewController (Not in TableView)

I am producing a JSON string that I need to parse out and display onto the page. My JSON string outputs information about the contents of a CD like this:
[{"song_name":"Song 1","artist":"John","price":"$1"},
{"song_name":"Song 2","artist":"Anna","price":"$2"},
{"song_name":"Song 3","artist":"Ryan","price":"$3"}]
I would like to display the contents in my viewController in a list format displaying the song_name, artist, and price. I do not want to use a tableView to display this information, but would rather just have a list displayed. How might I go about doing this? I would assume that I need to use NSJSONSerialization, but have only used that for a tableView in the past. Thank you!
In addition to other answers, you can use only one label, just create NSMutableString (for dynamicly adding tracks info) with #"\n" between tracks info, pass it to label.text and set UILabel's property numberOfLines to 0
Follow these steps:
Parse the JSON and store the key-value pair(NSDictionary of CDs) in an NSArray (say infoArray)
Add a UIScrollview as a subview on your viewController's view.
Allocate UILabels dynamically, depending on infoArray count. Looking at your data I believe you can initialize labels with static frames i.e your y can remain static.
Add the text from the infoArray on this label.
Still, I would suggest use UITableView only. It is much simpler and a better approach
You make an array of dictionaries using NSJSONSerialization indeed, then you parse this array one by one and create a view of every dictionary. You're probably best of using a method for this:
-(UIView *) listView: (NSString *)songName andArtist:(NSString *)artist andPrice:(NSString *)price andIndex:(int)viewIndex {
//create your view here and do anything you want
UIView *subView = [[UIView alloc] init] autoRelease];
subView.frame = CGRectMake(0, viewIndex * 70, self.view.frame.width, 70);
//add labels and other stuff
// return the view
return subView;
}
The you add it to the current view by setting different Y values so they appear underneath each other by using the viewIndex of the former method... So if you have an array it goes something like this:
for (int i = 0; i < [array count]; i++) {
NSDictionary *dict = [array objectAtIndex:i];
NSString *songName = [dict valueForKey:#"song_name"];
NSString *artist = [dict valueForKey:#"artist"];
NSString *price = [dict valueForKey:#"price"];
UIView *tempView = [self listView:songName andArtist:artist andPrice:price andIndex:i];
[self.view addSubView:tempView];
}
You have to add it all to a scrollview otherwise you will run into the problem of to many rows on the page. Google for UIScrollView if you don't know how.
But I would recommend against this approach.. Tableviews are there with a reason. They are made for this stuff. Because the also provide for scrolling, drawing and refreshing. If you can, use them!

NSArray to NSMutableArray

I am trying to pass an NSArray to a NSMutableArray but am having a few issues doing so and was hoping someone could help.
- (void)CachedData:(NSArray *)gArray indexPath:(NSIndexPath *)gIndex dataSetToParse:(NSString *)string
{
//Set dataSetToParse so the parsing delegates if statment works correctly
dataSetToParse = string;
//Calls method that sets the accessory tick
[self setAccessoryIndexPath:gIndex];
//Set array that can be used in this view
[parsedDataArray addObjectsFromArray:gArray];
//Use this method to pass NSData object to startTheParsingProcess method and also to initalize indexPathVariable
[self startSortingTheArray:gArray];
}
When I try to log parsedDataArray after I addObjects to it all I get is
(null)
(null)
.... etc.
any help would be appreciated.
Update
The main issue here is that I have 4 lots of arrays. with 3 views, a main view sub view and then a sub subview.
each array has a refrence ID to the next array, I want to parse each array before I display them to check if there are any values in them based off the restriction string. If there are no values then I will either send the user back to the main view or just not allow them to select the cell that has an array with no related values. (I hope you get what I am doing here)
The solution I have come up with for that is to parsed the values in the parent view of where I intend to display them...
if you look at my views
view 1
- view 2
-- view 3
I need a parsing delegate for view 1 and 2, because I need to check the values of view 3 in view 2.. However this is causing me an issue because I am using the same array to avid redundancy to return the value to the main view and create/check the values of the subview.
So I am trying to skip over the parser delegates of view 2 if i am not going to display anything in view 3, by passing my already parsed array into the mutablearray I will pass the data back with inside didselectcell method...
Anyway I hope this makes sense.. its the only way I think I can do this.. if you know better please let me know your strategy.
Assuming the parsedDataArray is a mutable array declared somewhere else, this wouldn't make sense:
//Set array that can be used in this view
[parsedDataArray addObjectsFromArray:parsedDataArray];
Unless you mean to double all of the objects in the parsedDataArray. I think what you meant is:
//Set array that can be used in this view
[parsedDataArray addObjectsFromArray:gArray];
But I can't be sure without more context or explanation.
check if garray is containing the data or not, by printing it in nslog
also check if u have intialized parsedDataArray as below or not
parsedDataArray=[[NSMutableArray alloc]init]; in Viewdidload delegate
NSArray *array = [NSArray arrayWithObjects:#"Raja",#"Ram",nil];
NSMutableArray *muArray = [NSMutableArray arrayWithArray:array];

Objective-C Memory Management Question, NSMutableArray

I have a UIViewController. At the top of the UIViewController, I have declared
NSMutableArray *contacts;
In my viewDidLoad method, I call [self getContacts] which basically initializes my contacts array. It begins by initializing the array, and then it adds some objects:
if(contacts == nil)
contacts = [[NSMutableArray alloc] init];
[contacts removeAllObjects];
[contacts addObjectsFromArray:[some objects]];
So, now my contacts is initialized. In my viewDidLoad method, I even use contacts, and it works great. Later on, in a method, I need to retrieve the elements of contacts, however I am getting an EXC_BAD_ACCESS. Why is this? Why doesn't my contacts array keep the objects that I initialized it with in the beginning, and how do I fix this?
EDIT:
The error comes when I select a NavigationBarItem which then triggers a method buttonWasPressed. In that method, I simply have the following:
-(void)buttonWasPressed:(id)sender {
NSLog(#"button was pressed");
if(contacts == nil)
NSLog(#"contacts is nil!");
NSLog(#"contacts = %#",contacts);
}
And I see "button was pressed" printed, but then there is an EXEC_BAD_ACCESS.
That code all looks good, nothing wrong there. I would guess you are over-releasing elsewhere. Turn on Zombies - add NSZombieEnabled to YES in the executable arguments and it will break on the line so you can see what object is being over-released.

creating a Mutable array that can be added to in later clicks of the same button?

General noob questions:
(1) How can I create an NSMutable array in a buttonClicked action that I can add more entries to during subsequent clicks of the same button? I always seem to start over with a new array at every click (the array prints with only 1 entry which is the most recent button's tag in an NSLog statement).
I have about 100 buttons (one for each character in my string called "list") generated by a for-loop earlier in my code, and each has been assigned a tag. They are in a scrollview within the view of my ViewController.
I wish to keep track of how many (and which ones) of the buttons have been clicked with the option of removing those entries if they are clicked a second time.
This is what I have so far:
-(void) buttonClicked:(UIButton *)sender
NSMutableArray * theseButtonsHaveBeenClicked = [[NSMutableArray alloc] initWithCapacity: list.length];
NSNumber *sendNum = [NSNumber numberWithInt:sender.tag];
[theseButtonsHaveBeenClicked addObject:sendNum at index:sender.tag];
NSLog(#"%#",theseButtonsHaveBeenClicked);
}
(2) I have read that I may be able to use a plist dictionary but I don't really understand how I would accomplish that in code since I cant type out the items in the dictionary manually (since I don't know which buttons the user will click). Would this be easier if I somehow loaded and replaced the dictionary in a plist file? And how would I do that?
(3) I also have no idea how I should memory manage this since I need to keep updating the array. autorelease?
Thanks for any help you can provide!
Okay, firstly you are creating a locally scoped array that is being re-initialised on every call to buttonClicked:. The variable should be part of the class init cycle.
You will also be better off with an NSMutableDictionary instead of an NSMutableArray. With a dictionary we don't have to specify capacity and we can use the button's tags as dictionary keys.
Here's what you need to do, these three steps always go together: property/synthesize/release. A good one to remember.
//Add property declaration to .h file
#property (nonatomic, retain) NSMutableDictionary * theseButtonsHaveBeenClicked;
//Add the synthesize directive to the top of .m file
#synthesize theseButtonsHaveBeenClicked;
// Add release call to the dealloc method at the bottom of .m file
- (void) dealloc {
self.theseButtonsHaveBeenClicked = nil; // syntactically equiv to [theseButtonsHaveBeenClicked release] but also nulls the pointer
[super dealloc];
}
Next we create a storage object when the class instance is initialised. Add this to your class's init or viewDidLoad method.
self.theseButtonsHaveBeenClicked = [[NSMutableDictionary alloc] dictionary]; // convenience method for creating a dictionary
And your updated buttonClicked: method should look more like this.
-(void) buttonClicked:(UIButton *)sender {
NSNumber *senderTagAsNum = [NSNumber numberWithInt:sender.tag];
NSString *senderTagAsString = [[NSString alloc] initWithFormat:#"%#",senderTagAsNum];
// this block adds to dict on first click, removes if already in dict
if(![self.theseButtonsHaveBeenClicked objectForKey:senderTagAsString]) {
[self.theseButtonsHaveBeenClicked setValue:senderTagAsNum forKey:senderTagAsString];
} else {
[self.theseButtonsHaveBeenClicked removeObjectForKey:senderTagAsString]; }
[senderTagAsString release];
NSLog(#"%#", self.theseButtonsHaveBeenClicked);
}

Dynamically selecting different viewControllers

I've got a problem that I think is probably straight forward but I can't seem to wrap my head around it.
I've got a tableview that loads from an array of NSDictionaries. Each Dictionary has a title (shown in the row) and an associated nssstring representing a viewcontroller that should be pushed onto the stack when the row is selected. In other words, selecting row "A" needs to initialize an instance of "aViewController" and push it on the stack, selecting row "B" needs to initialize an instance of "bViewController" and push it on the stack, etc.
I originally just hardcoded all possible values into didSelectRow. But I'd really like to be able to dynamically generate the viewController dynamically. I found a few C++ examples of similar problems that led me to the code below. But I can't seem to get it right and am not sure I'm on the right track for an objective-c solution. Anyone have any thoughts?
Here's the didSelectRow code that's not working:
Class cls = [selectedRow valueForKey:#"viewController"];
if (cls!= nil)
{
id myNewController = [[cls alloc] init];
}
[[self navigationController] pushViewController:myNewController animated:YES];
[myController release];
Are you storing the actual Class or the class name (as an NSString) in the dictionary?
If the value you are storing in the dictionary is an NSString I don't think you can just assign Class cls = someNSString;
You can, however, do:
NSString *controllerClassName = [selectedRow valueForKey:#"viewController"];
if (controllerClassName != nil) {
id myNewController = [[NSClassFromString(controllerClassName) alloc] init];
[[self navigationController] pushViewController:myNewController animated:YES];
[myNewController release];
}
OR
Just store the Class in the dictionary instead of the NSString representation: