NSMutableArray vs NSArray Round 2 - iphone

my question depends on my other question
NSMutableArray vs NSArray
i have created a navigationController and load a TableView inside with data from the other question. Now a get a detailview and get new data from xml, so i copy my methods and modifide them.
but it is the same stucture, i does not change a lot.
But now i get the same error.
i have in detailview.h
NSMutableArray *seminareArray;
and
#property (nonatomic, retain) NSMutableArray *seminareArray;
in detailview.m
#synthesize SeminareListeTabelle, selectedSeminar, seminareArray, receivedData;
i add this code
seminareArray = [[NSMutableArray alloc] init];
self.seminareArray = [NSMutableArray arrayWithCapacity:10];
before i add the data. and i get the error here
cell.textLabel.text = [seminareArray objectAtIndex:row];
EXC_BAD_ACCESS again some type problem
i add data to array like this
if([elementName isEqualToString:#"seminar"])
{
//NSLog(#"%#", [attributeDict objectForKey:#"name"]);
NSString *seminarName = [NSString stringWithFormat:#"%#", [attributeDict objectForKey:#"name"]];
[seminareArray addObject:seminarName];
[seminarName release];
}
the array is filled with data, but after tableView reload, i get this error.
//
// SeminareListingView.m
// Seminar App2
//
// Created by Alexander Frischbutter on 05.07.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "SeminareListingView.h"
//#import "SeminareView.h"
#implementation SeminareListingView
#synthesize SeminareListeTabelle, selectedSeminar, seminareArray, receivedData;
- (void) parseData:(NSString *)url
{
if(receivedData)
{
receivedData = nil;
}
NSLog(#"Parsing... url: %#", url);
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#", url]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(theConnection)
{
receivedData = [[NSMutableData data] retain];
}
else
{
//label.text = #"XML nicht geladen";
NSLog(#"XML nicht gefunden");
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
SeminareListeTabelle = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
SeminareListeTabelle.delegate = self;
SeminareListeTabelle.dataSource = self;
SeminareListeTabelle.autoresizesSubviews = YES;
seminareArray = [[NSMutableArray alloc] init];
self.seminareArray = [NSMutableArray arrayWithCapacity:10];
[self parseData:[NSString stringWithFormat:#"http://akademie.kunden.fincha.com/semapp/sem_kat_arbtechnik.xml", selectedSeminar]];
self.navigationItem.title = [NSString stringWithFormat:#"%#", selectedSeminar];
self.view = SeminareListeTabelle;
// Do any additional setup after loading the view from its nib.
}
- (void)startParsingData
{
NSLog(#"Parsing started");
NSXMLParser *dataParser = [[NSXMLParser alloc] initWithData:receivedData];
dataParser.delegate = self;
[dataParser parse];
[dataParser release];
[receivedData release];
NSLog(#"Received Data in seminareArray");
/*
for(int i = 0; i < [seminareArray count]; i++)
{
NSLog(#"%d is %#", i, [seminareArray objectAtIndex:i]);
//NSLog(#"Count %d", [kategorienArray count]);
}
*/
//[seminareArray release];
NSLog(#"Reload data in TableView");
[self.SeminareListeTabelle reloadData];
NSLog(#"Data reloaded");
}
- (void)viewDidUnload
{
//[seminareArray release];
//[SeminareListeTabelle release];
NSLog(#"Vew unloaded");
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil) { cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier] autorelease];
}
if([seminareArray count] != 0)
{
NSLog(#"Adding data to cell");
NSUInteger row = [indexPath row];
//cell.textLabel.text = [NSString stringWithFormat:#"bla, %d", row]; //[seminareArray objectAtIndex:row];
cell.textLabel.text = [seminareArray objectAtIndex:row];
NSLog(#"Added data to cell");
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//NSLog(#"Count %d", [self.seminareArray count]);
return [seminareArray count];
}
-(NSInteger) tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 0;
}
//Anzeige mit Seminaren öffnen bei Click auf die Zeile
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//gehe zurück zum ersten View
//NSLog(#"Received Data in seminareArray");
[[self navigationController] popViewControllerAnimated:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveResonse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if(receivedData)
{
[receivedData appendData:data];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection release];
[receivedData release];
//label.text = #"Connection failed";
NSLog(#"Verbindung fehlgeschlagen!");
//[[self navigationController] popViewControllerAnimated:YES];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self startParsingData];
[connection release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
//NSLog(#"Parser was called. Element: %#", elementName);
if([elementName isEqualToString:#"seminar"])
{
//NSLog(#"%#", [attributeDict objectForKey:#"name"]);
NSString *seminarName = [NSString stringWithFormat:#"%#", [attributeDict objectForKey:#"name"]];
[seminareArray addObject:seminarName];
[seminarName release];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"Parse Error %#", parseError);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end

The problem stems from this code:
seminareArray = [[NSMutableArray alloc] init]; // owned
seminareArray = [NSMutableArray arrayWithCapacity:10]; // autoreleased
You're first initializing the semiareArray as an owned object, but then are re-setting it as an autoreleased object.
Meaning, it will be released after the run-loop terminates.
Remove the second (autoreleased) statement but keep the first, and everything should work fine.
The reason why you're getting the EXC_BAD_ACCESS error is because the seminareArray object is released at some point before it being used again.
Additionally, try to debug your
cell.textLabel.text = [seminareArray objectAtIndex:row];
Try setting it as id var = [seminareArray objectAtIndex:row]; and then setting cell.textLabel.text = var; This will tell you if the error occurs due to array being dealloc'd too early, or improper cell/textLabel.
Updated:
There's an additional problem is with the code:
NSString *seminarName = [NSString stringWithFormat:#"%#", [attributeDict objectForKey:#"name"]];
[seminareArray addObject:seminarName];
[seminarName release]; // <--
You're creating an auto-released object seminarName, which technically has retain count 0. You're adding it to the semiareArray, which ups the object retain count to 1. Then you're releasing it again. Which causes it to be dealloc'd at runtime. The problem is that when you're assigning the value to the textLabel, the object no longer exists.
Solution: remove the [seminarName release]; Don't worry about releasing the seminarName, since it's auto-released, it will be released when the array is dealloc'd, or when the object it removed from the array.

David's answer is correct but I would advice reading up on your memory management.
If you are synthesizing properties then it is a lot easier to use the getters and setters and let them do the memory management for you. The exception being in your init/dealloc methods where you should try to directly use the ivars to avoid any potential side effects of using the getters/setters.
With the two lines david highlighted
seminareArray = [[NSMutableArray alloc] init]; // owned
seminareArray = [NSMutableArray arrayWithCapacity:10]; // autoreleased
You could potentially use either if the memory management was done correctly.
The first line on its own is correct as it creates an instance of NSMutableArray with a retain count of +1 then assigns it straight to the ivar.
Then as David pointed out the second line replaces this with an autoreleased NSMutableArray so this line is superflous and crashes your program. The method arrayWithCapacity: is not simply setting the capacity of the array it is giving you a new autoreleased array.
If you wanted to use an autoreleased NSMutableArray then you would need to use the setter either with dot notation of passing a message:
self.seminareArray = [NSMutableArray arrayWithCapactiy:10];
OR
[self setSeminareArray:[NSMutableArray arrayWithCapcity:10]];
By simply referencing things straight to seminareArray you are avoiding the getters/setters you synthesized and therefore are responsible for all of your memory management.

A hint at a memory leak:
self.seminareArray = [[NSMutableArray alloc] init];
this will leak memory because seminare is declared as retained property:
#property (nonatomic, retain) NSMutableArray *seminareArray;
This is not, anyway, the cause of your other issue.
The error you are having is caused by row being greater that the count of your array. So either you don't add sufficient objects to the array, or you try to use an incorrect value for row. Inspect that line with a debugger and ensure that row never goes beyond [seminare count]; you will find out easily why it happens.

Related

Trying to Save/Load Array Data to Plist

I've been learning Objective C and the iPhone SDK gradually, and my current project involves building an application that stores numerical data (sports data). This is primarily for learning purposes, as there are multiple apps that do the same thing. Anyway, I've hit a bit of a snag. My intention is to have a list of players stored in a table and allow the user to add additional players.
At the moment, I have a button that when pressed, "Ninjas" will be added to the table. I've also enabled deleting in the table. Unfortunately, I can't seem to figure out how to save and load the data from a plist. I followed various tutorials and guides, but I can't figure out what's happening. My suspicion is I am loading the data from an empty array and adding to that array, but the array involving the data is a separate array from the plist. Unfortunately, I am a bit lost beyond that.
The data in my array is erased whenever I switch views. However, I've noticed that the data remains if I leave and come back, but not if I leave for a considerable amount of time, leave and restart the iphone, etc. This seems to occur even for apps that I have not worked on saving. Is this just a function of the iPhone holding onto data in case a user accidentally exits a program?
Hopefully I explained my issue somewhat tangibly. TL:DR version: I want to add data to an array, save it to a plist, and reload the data from the plist whenever the array is present on the screen. Code below is attempting to accomplish this, but it isn't succeeding.
Thanks
#import "RootViewController.h"
#import "NewPlayer.h"
#import "OptionsMenu.h"
#implementation RootViewController
#synthesize createdPlayers;
#synthesize listOfPlayers;
-(NSString *) pathOfFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [paths objectAtIndex:0];
return [documentFolder stringByAppendingFormat:#"myfile.plist"];
}
-(void)applicationWillTerminate:(NSNotification*)notification{
NSMutableArray *array = [[NSMutableArray alloc]init];
[array writeToFile: [self pathOfFile] atomically:YES];
}
- (void)viewDidLoad
{
NSString *filePath = [self pathOfFile];
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
listOfPlayers.array = [array objectAtIndex:0];
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];
[super viewDidLoad];
listOfPlayers = [[NSMutableArray alloc] init];
}
-(IBAction)AddButtonAction:(id)sender{
[listOfPlayers addObject:#"Ninjas"];
[createdPlayers reloadData];
}
-(IBAction)switchView:(id)sender{
OptionsMenu *second = [[OptionsMenu alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
}
-(IBAction)newView:(id)sender{
NewPlayer *second = [[NewPlayer alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated: YES];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [listOfPlayers count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = UITextAlignmentCenter;
NSString *cellValue = [listOfPlayers objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSLog(#"delete section: %d rol: %d", [indexPath indexAtPosition:0], [indexPath indexAtPosition:1]);
[listOfPlayers removeObjectAtIndex:[indexPath indexAtPosition:1]];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
-(void)tableView:(UITableView *)listOfPlayers moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath{
}
-(void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc{
[createdPlayers release];
[listOfPlayers release];
[super dealloc];
}
#end
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView* createdPlayers;
IBOutlet UIButton* superCat;
NSMutableArray *listOfPlayers;
}
#property(nonatomic, retain) IBOutlet NSObject *listOfPlayers;
-(NSString *) pathOfFile;
-(void)applicationWillTerminate:(NSNotification*)notification;
-(IBAction)AddButtonAction:(id)sender;
-(IBAction)switchView:(id)sender;
-(IBAction)newView:(id)sender;
#property (nonatomic, retain) UITableView* createdPlayers;
#end
Code update 20th Dec:
-(NSString *) pathOfFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [paths objectAtIndex:0];
return [documentFolder stringByAppendingFormat:#"myfile.plist"];
}
-(void)applicationWillTerminate:(NSNotification*)notification
{
[self.listOfPlayers writeToFile:[self pathOfFile] atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
- (void)viewDidLoad
{
self.listOfPlayers = [[NSMutableArray alloc] init];
NSString *filePath = [self pathOfFile];
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
self.listOfPlayers = array;
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];
[super viewDidLoad];
}
I don't know plist. But you can try use NSData
NSArray *array;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
//Write data
[data writeToFile:filePath atomically:YES];
//Read data
NSFileManager *fileManager = [NSFileManager defaultManager];
NSData *oldData = [fileManager contentsAtPath:filePath];
NSArray *newArray = [NSKeyedUnarchiver unarchiveObjectWithData:oldData]
Welcome to the world of iOS programming. It's a lot of fun, but it can be frustrating, just as programming in any language can be. I feel your pain.
There are a number of things that I see:
In viewDidLoad, it appears that your code to read your file into an array is okay, but then it appears as if you're trying to assign only the first row of this array to your listOfPlayers. Try:
self.listOfPlayers = array;
array is an array, and so is your listOfPlayers. Also, using self will ensure that the synthesized setter is used, thus retaining your listOfPlayers when you release array.
In applicationWillTerminate, I believe you wish to write your listOfPlayers to a file, but what you are actually doing is allocating and initializing an empty array, and writing THAT to your file. Try:
-(void)applicationWillTerminate:(NSNotification*)notification
{
[self.listOfPlayers writeToFile: [self pathOfFile] atomically:YES];
}
I hope this helps!
There seems something wrong in your viewDidLoad
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
listOfPlayers.array = [array objectAtIndex:0];
.
.
}
.
.
.
listOfPlayers = [[NSMutableArray alloc] init];
You are accessing listOfPlayers before ever allocating it.
listOfPlayers.array is wrong as well

Confusing double free error message/memory leak in iPhone app

EDIT - added .h file
I'm having difficulty trying to find the cause of a double free error.
Steps taken to solve
1) Used the Zombies tool. Zombies reports that tid is being double freed
2) Set a breakpoint on malloc_error_break. This identifitied the following code segment as faulty:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[connection release];
[ldestination release];
[ldeparts_from release];
[ltime release];
[lcs_id release]; /// It breaks here
[carsharexml release];
}
3) I looked through the code to see where I had [lcs_id release] before - I found nothing.
4) In a desperate attempt to solve it I commented out [lcs_id release]. This stopped the
double free error messages but when I ran it through leaks it said that this was causing memory leaks.
What am I doing wrong?
Thanks very much.
Below is a complete copy of the code:
#import <UIKit/UIKit.h>
#import "MyManager.h"
#interface ListOfCarShares : UITableViewController <NSXMLParserDelegate>
{
NSURLConnection *connection;
NSMutableData *carsharexml;
NSMutableArray *ldestination;
NSMutableArray *ldeparts_from;
NSMutableArray *lcs_id;
NSMutableArray *ltime;
NSMutableString *currentElement;
NSMutableString *tdest;
NSMutableString *tfrom;
NSMutableString *ttime;
NSMutableString *tid;
}
-(void)fetchcarshares;
#property (nonatomic, assign) IBOutlet UITableViewCell *maincell;
#end
//
// ListOfCarShares.m
// Warwick_Culture
//
// Created by Me on 26/10/2011.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "ListOfCarShares.h"
#implementation ListOfCarShares
#synthesize maincell;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:#"destination"])
{
//NSLog(#"found current conditions tag it reads %#",currentElement);
tdest = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"departs_from"])
{
tfrom = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"time"])
{
ttime = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"cs_id"])
{
tid = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"destination"])
{
[tdest appendString:string];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[tfrom appendString:string];
}
if ([currentElement isEqualToString:#"time"])
{
[ttime appendString:string];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[tid appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([currentElement isEqualToString:#"destination"])
{
[ldestination addObject:tdest];
[tdest release];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[ldeparts_from addObject:tfrom];
[tfrom release];
}
if ([currentElement isEqualToString:#"time"])
{
[ltime addObject:ttime];
[ttime release];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[lcs_id addObject:tid];
[tid release];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
ldestination = [[NSMutableArray alloc] init];
ldeparts_from = [[NSMutableArray alloc] init];
ltime = [[NSMutableArray alloc] init];
lcs_id = [[NSMutableArray alloc] init];
carsharexml = [[NSMutableData alloc] init];
[self fetchcarshares];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[connection release];
[ldestination release];
[ldeparts_from release];
[ltime release];
[lcs_id release]; ///
[carsharexml release];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [ltime count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"carsharecell" owner:self options:nil];
}
// Configure the cell...
cell=maincell;
UILabel *from;
UILabel *dest;
UILabel *time;
from = (UILabel *)[cell viewWithTag:4];
dest = (UILabel *)[cell viewWithTag:5];
time = (UILabel *)[cell viewWithTag:6];
from.text=[ldeparts_from objectAtIndex:indexPath.row];
dest.text=[ldestination objectAtIndex:indexPath.row];
time.text=[ltime objectAtIndex:indexPath.row];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
-(void)fetchcarshares
{
MyManager *sharedManager = [MyManager sharedManager];
NSString *urlString = [NSString stringWithFormat:#"http://url/get.php?username=%#&password=%#",sharedManager.user,sharedManager.passw];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[carsharexml appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)conn
{
NSString *xmlcheck = [[NSString alloc] initWithData:carsharexml encoding:NSUTF8StringEncoding];
NSLog(#"%#",xmlcheck);
[xmlcheck release];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData: carsharexml];
[parser setDelegate:self];
[parser parse];
[parser release];
[[self tableView] reloadData];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 102;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
-(void)dealloc
{
[super dealloc];
}
#end
Try this....
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
ldestination = [[[NSMutableArray alloc] init]retain];
ldeparts_from = [[[NSMutableArray alloc] init]retain];
ltime = [[[NSMutableArray alloc] init]retain];
lcs_id = [[[NSMutableArray alloc] init]retain];
carsharexml = [[[NSMutableData alloc] init]retain];
[self fetchcarshares];
}
if lcs_id property not define as retain you need to replace the line
lcs_id = [[NSMutableArray alloc] init];
to
lcs_id = [[[NSMutableArray alloc] init] retain];
or another work around would be in
- (void)viewWillDisappear:(BOOL)animated
{
if(lcs_id)
{
[lcs_id release];
lcd_id = nil;
}
}
For the Crashing issue, please check below point
1. Please make sure you haven't use [autorelease] for object lcs_id
2. Most important, if you have use same variable in other pages in application, you have received above error.
please try
[this.lcs_id release]
Your error will resolved.

dealloc vs ViewDidDissapear for memory management

I have a few views which parse xml downloaded from the internet.
The instruments leaks tool tells me I have leaks when I release data members inside the dealloc method but not when i put the [objectname release]; inside viewDidDissapear.
Is this a cardinal sin?
Coming from a c/c++ background I find obj-c memory management very confusing!
EDIT: Here is the code:
#import "SuggestedFriendList.h"
#implementation SuggestedFriendList
#synthesize maincell,nationalityimageview, subjectimageview, accommodationimageview;
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:#"shared"])
{
tshared = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"fullname"])
{
tfullname = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"nationality"])
{
tnationality = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"subject"])
{
tsubject = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"accommodation"])
{
taccommodation = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"memberid"])
{
tmemberid = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"count"])
{
tcount = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"shared"])
{
[tshared appendString:string];
}
if ([currentElement isEqualToString:#"fullname"])
{
[tfullname appendString:string];
}
if ([currentElement isEqualToString:#"nationality"])
{
[tnationality appendString:string];
}
if ([currentElement isEqualToString:#"subject"])
{
[tsubject appendString:string];
}
if ([currentElement isEqualToString:#"accommodation"])
{
[taccommodation appendString:string];
}
if ([currentElement isEqualToString:#"memberid"])
{
[tmemberid appendString:string];
}
if ([currentElement isEqualToString:#"count"])
{
[tcount appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"shared"])
{
[lshared addObject:tshared];
[tshared release];
}
if ([elementName isEqualToString:#"fullname"])
{
[lfullname addObject:tfullname];
[tfullname release];
}
if ([elementName isEqualToString:#"nationality"])
{
[tnationality appendString:#".png"];
[lnationality addObject:tnationality];
[tnationality release];
}
if ([elementName isEqualToString:#"subject"])
{
[lsubject addObject:tsubject];
[tsubject release];
}
if ([elementName isEqualToString:#"accommodation"])
{
[laccommodation addObject:taccommodation];
[taccommodation release];
}
if ([elementName isEqualToString:#"memberid"])
{
[lmemberid addObject:tmemberid];
[tmemberid release];
}
if ([elementName isEqualToString:#"count"])
{
count = [[NSMutableString alloc] init];
count = tcount;
[tcount release];
}
}
-(void)fetchsuggestions
{
MyManager *sharedManager = [MyManager sharedManager];
suggestiondetailxml = [[NSMutableData alloc] init];
NSString *urlString = [NSString stringWithFormat:#"http://secreturl.com/a.php?username=%#&password=%#",sharedManager.user,sharedManager.passw];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[suggestiondetailxml appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)conn
{
NSString *xmlcheck = [[[NSString alloc] initWithData:suggestiondetailxml encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"%#",xmlcheck);
lshared = [[NSMutableArray alloc] init];
lfullname = [[NSMutableArray alloc] init];
lnationality = [[NSMutableArray alloc] init];
lsubject = [[NSMutableArray alloc] init];
laccommodation = [[NSMutableArray alloc] init];
lmemberid = [[NSMutableArray alloc] init];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData: suggestiondetailxml];
[parser setDelegate:self];
[parser parse];
[parser release];
//[xmlcheck release]; //causes crash
[connection release];
connection = nil;
[suggestiondetailxml release];
[[self tableView] reloadData];
NSLog(#"%#",lmemberid);
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[[self navigationItem] setTitle:#"My Culture"];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self fetchsuggestions];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[lshared release];
[lfullname release];
[lnationality release];
[lsubject release];
[laccommodation release];
[lmemberid release];
//[count release];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [lfullname count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 93.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell==nil)
{
[[NSBundle mainBundle] loadNibNamed:#"SuggestedFriendCell" owner:self options:nil];
cell = maincell;
//self.detailcell = nil;
}
UILabel *name;
name = (UILabel *)[cell viewWithTag:4];
name.text=[lfullname objectAtIndex:indexPath.row];
if(([[lshared objectAtIndex:indexPath.row]isEqualToString:#"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"nationalityandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"nationalityandsubject"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"nationality"]))
{
UIImageView *nationality;
nationality = (UIImageView *)[cell viewWithTag:1];
nationality.image=[UIImage imageNamed:[lnationality objectAtIndex:indexPath.row]];
}
if(([[lshared objectAtIndex:indexPath.row]isEqualToString:#"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"nationalityandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"subjectandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"accommodation"]))
{
UIImageView *accommodation;
accommodation = (UIImageView *)[cell viewWithTag:2];
accommodation.image=[UIImage imageNamed:#"accommodation.jpeg"];
}
if(([[lshared objectAtIndex:indexPath.row]isEqualToString:#"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"nationalityandsubject"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"subjectandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:#"subject"]))
{
UIImageView *subject;
subject = (UIImageView *)[cell viewWithTag:3];
subject.image=[UIImage imageNamed:#"degree.jpg"];
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
MyManager *sharedManager = [MyManager sharedManager];
int row = indexPath.row;
sharedManager.interrogatedmemberid=[lmemberid objectAtIndex:row];
ViewFriendProfile *frienddetail_vc = [[[ViewFriendProfile alloc] init] autorelease];
[[self navigationController] pushViewController:frienddetail_vc animated:YES];
}
-(void)dealloc
{
[super dealloc];
}
#end
When I uncomment [tcount release] it causes crashes: why is this.
PS: I am SO sorry about the formatting: How can you copy and paste code so it appears in the code blocks?
Thanks
To understand what's going on you need to understand how viewWillAppear and viewWillDisappear work.
Both methods are invoked multiple times in a view controller's life cycle depending on whether you're pushing/popping a viewcontroller, or if you're displaying / dismissing a modal from a view controller.
For example:
Push viewController A: viewDidLoad and viewWillAppear called on viewController A
Push viewController B from viewController A: viewWillDisappear called on viewController A, viewDidLoad and viewWillAppear called on viewController B
Pop viewController B to go back to viewController A: viewWillDisappear called on viewController B, viewDidUnload called on viewController B, dealloc called on viewController B, viewWillAppear called on viewController A
Display a modal from viewController A: viewWillDisappear called on viewController A
Dismiss the modal: viewWillAppear called on viewController A
Pop viewController A: viewWillDisappear called on viewController A, viewDidUnload called on viewController A, dealloc called on viewController A
Sounds like you're allocating an object in viewWillAppear, which is called multiple times, but deallocating it in the dealloc method, which is called only once, hence the memory leak.
Releasing your object in viewWillDisappear is balancing out the allocs in viewWillAppear hence there is no leak.
All I can say at this point is, unless you have a very good reason to allocate something in viewWillAppear (i.e., you know what you're doing), don't do it.
There's not much more I can tell you... posting more code for what you're trying to do might help you get a more elaborate answer :)
Hope this helped though.
EDIT after the code was posted.
First of all, do you mean 'when I uncomment [count release]'? Could you post the console message for that crash? It's crashing because parserDidEndElement is where it's allocated, but it is getting released in viewWillDisappear. If these don't balance out, you'll get an EXC_BAD_ACCESS
Coming to your memory situation. I see now why releasing in viewWillDisappear fixes the leaks. You're calling fetchsuggestions on viewWillAppear which in turn creates and fires off the URL request. This will lead to connectionDidFinishLoading being called on a successful connection. Here is where you're allocating the various ivars. Since I mentioned earlier that viewWillAppear is called multiple times, this means that you're firing off the connection multiple times which leads to connectionDidFinishLoading being called multiple times.
That is why releasing in viewWillDisappear fixes the leaks because for every allocate on a viewWillAppear, you balance it by releasing in viewWillDisappear.
What you missed though is that your program will crash when there's no network available. This is because connectionDidFinishLoading will not get called when there's no network. Now, when you try releasing in viewWillDisappear, you will get an EXC_BAD_ACCESS as you're trying to release previously deallocated instances which were never allocated again in viewWillAppear.
I don't think I see a need to call fetchsuggestions multiple times on viewWillAppear, unless you're doing it intentionally.
This is the most glaring thing I see right now... the issues could be (and probably are) multiple, but how about we start off by restructuring the code keeping in mind that multiple unbalanced allocs and releases inside viewWillAppear/Disappear might not be a good idea...? :)
It's kind of strange to release anything in viewWillDisappear, but if you allocate it in viewWillAppear, that's the right thing to do. I think you should be allocating your objects in viewDidLoad, and releasing them in viewDidUnload. In some cases that would avoid unnecessarily recreating them.
You should also release retained ivars in dealloc. Just make sure that when you release them in other methods, you set them to nil, so if they get released again, it's just sending release to nil, which is a no-op.
One tool that I find helpful in finding potential memory leaks is Build > Analyse in Xcode.
It tells you which line did the allocation and where might it leak later down the code. It also tells you where you have made incorrect [object release] decrement count.
There is a possibilty that you are not completely releasing the view and dealloc is never being called.

When to use properties in objective C?

I have a question here: Confusing double free error message/memory leak in iPhone app which I think needs a new question to answer it.
The code I am interested in is in that question but I will re post it here
#import <UIKit/UIKit.h>
#import "MyManager.h"
#interface ListOfCarShares : UITableViewController <NSXMLParserDelegate>
{
NSURLConnection *connection;
NSMutableData *carsharexml;
NSMutableArray *ldestination;
NSMutableArray *ldeparts_from;
NSMutableArray *lcs_id;
NSMutableArray *ltime;
NSMutableString *currentElement;
NSMutableString *tdest;
NSMutableString *tfrom;
NSMutableString *ttime;
NSMutableString *tid;
}
-(void)fetchcarshares;
#property (nonatomic, assign) IBOutlet UITableViewCell *maincell;
#end
#import "ListOfCarShares.h"
#implementation ListOfCarShares
#synthesize maincell;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:#"destination"])
{
//NSLog(#"found current conditions tag it reads %#",currentElement);
tdest = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"departs_from"])
{
tfrom = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"time"])
{
ttime = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"cs_id"])
{
tid = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"destination"])
{
[tdest appendString:string];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[tfrom appendString:string];
}
if ([currentElement isEqualToString:#"time"])
{
[ttime appendString:string];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[tid appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([currentElement isEqualToString:#"destination"])
{
[ldestination addObject:tdest];
[tdest release];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[ldeparts_from addObject:tfrom];
[tfrom release];
}
if ([currentElement isEqualToString:#"time"])
{
[ltime addObject:ttime];
[ttime release];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[lcs_id addObject:tid];
[tid release];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
ldestination = [[NSMutableArray alloc] init];
ldeparts_from = [[NSMutableArray alloc] init];
ltime = [[NSMutableArray alloc] init];
lcs_id = [[NSMutableArray alloc] init];
carsharexml = [[NSMutableData alloc] init];
[self fetchcarshares];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[connection release];
[ldestination release];
[ldeparts_from release];
[ltime release];
[lcs_id release]; ///
[carsharexml release];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [ltime count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"carsharecell" owner:self options:nil];
}
// Configure the cell...
cell=maincell;
UILabel *from;
UILabel *dest;
UILabel *time;
from = (UILabel *)[cell viewWithTag:4];
dest = (UILabel *)[cell viewWithTag:5];
time = (UILabel *)[cell viewWithTag:6];
from.text=[ldeparts_from objectAtIndex:indexPath.row];
dest.text=[ldestination objectAtIndex:indexPath.row];
time.text=[ltime objectAtIndex:indexPath.row];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
-(void)fetchcarshares
{
MyManager *sharedManager = [MyManager sharedManager];
NSString *urlString = [NSString stringWithFormat:#"http://url/get.php?username=%#&password=%#",sharedManager.user,sharedManager.passw];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[carsharexml appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)conn
{
NSString *xmlcheck = [[NSString alloc] initWithData:carsharexml encoding:NSUTF8StringEncoding];
NSLog(#"%#",xmlcheck);
[xmlcheck release];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData: carsharexml];
[parser setDelegate:self];
[parser parse];
[parser release];
[[self tableView] reloadData];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 102;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
-(void)dealloc
{
[super dealloc];
}
#end
I only have one property defined in the .h file. The people who answered that question seem to think that the reason I am having double free error is due to the fact I don't have #property for my variables.
I have lots of code practically identical to this and I don't have a problem.
My questions are
When should I use a property?
Should I be using properties here and why?
Thanks
You technically only need to use properties for values that are intended to be accessible from other classes, but many find it easier to use (retained) properties for all pointer-type instance variables so that the retaining is a bit more automatic. (And then use self.propertyName = xxx; notation for setting and self.propertyName = nil; for releasing in dealloc.)
Yes, you can do the retains and releases "manually", but it's a hair tedious to do so, and you tend to muck things up when you make "quick edits". The one thing you have to watch out for, though, is assigning a retained (not simply autoretained) value (such as your alloc/init values) to a self.xxx property. This will result in double retain, if you don't mitigate it somehow.
Another thing to do, if you don't use properties, is to always nil a pointer value after you release it. This prevents you from accidentally using the released value and and it prevents you from doing a double release.
(Note that it's in no way "bad programming" to use "lazy" techniques like I described above, vs "perfectly" figuring out everything. About 98% of programming is debugging, and anything you can do to prevent bugs or make them easier to find is goodness.)
(I'll also note that your problem in the above code appears to be mainly that you do not nil thetdest et al pointers after releasing them. And your if tests should likely check to see if the pointer has been nilled before using it.)
Added: Note that the above applies to pre-ARC programs. With ARC the "rules" change substantially.
Properties do a lot of things. At the most superficial level, they let you access your member variables in dotted form. At best, they can be excellent memory management tools (and more).
Let's say you have a variable:
NSNumber * myNumber;
Later in the code, you access it as:
myNumber = [NSNumber numberWithInt: 5];
The problem is that you might lose reference to the previously stored value in myNumber. Possible Memory Leak!! At this point, you don't have a retain on myNumber and it may get dealloc'd before you're done using it.
How can properties help? Let's say you defined a property around it and used synthesize:
In the interface definition:
NSNumber * myNumber;
...
#property (retain, nonatomic) NSNumber * myNumber;
and
In the implementation file:
#synthesize myNumber;
This will create a getter and setter. Meaning... everytime you assign myNumber to something as in:
self.myNumber = newNumber;
the following setter method (created by synthesize directive) gets invoked:
- (NSNumber *) setMyNumber: (NSNumber *) newNumber {
[myNumber release];
myNumber = newNumber;
[myNumber retain];
return newNumber;
}
Here, myNumber gets a retain automatically. This is very tedious to do by hand everytime... as you can see, it's much easier to use properties.
This is still not a perfect solution, though! Why? What if you use the following statement in your implementation:
myNumber = newNumber;
Remember, properties' getter and setter get invoked only if you're using the dotted notation (self.myNumber). So here, using properties has done nothing for us, 'cause we forgot to use them!
This is very common and likely lapse and understandingly frustrating.
So, what's the best way? This is what I recommend (as do countless others):
In the interface class:
NSNumber * _myNumber;
...
#property (retain, nonatomic) NSNumber * myNumber;
In the implementation file:
#synthesize myNumber = _myNumber;
Now, you can access your-number as:
self.myNumber = whateverNewNumber;
But, if you did:
myNumber = whateverNewNumber;
You'll get an error... because myNumber variable just doesn't exist... forcing you to use self.myNumber everytime!
Also, if you do choose to go this route, don't forget the dealloc:
- (void) dealloc {
[_myNumber release];
_myNumber = nil;
}
or more succinct:
- (void) dealloc {
self.myNumber = nil;
}

Help with iphone dev - beyond bounds error

I'm just learning iphone development, so please forgive me for what is probably a beginner error. I've searched around and haven't found anything specific to my problem, so hopefully it is an easy fix.
The book has examples of building a table from data hard coded via an array. Unfortunately it never really tells you how to get data from a URL, so I've had to look that up and that is where my problems show up.
When I debug in xcode, it seems like the count is correct, so I don't understand why it is going out of bounds?
This is the error message:
2010-05-03 12:50:42.705 Simple Table[3310:20b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (1) beyond bounds (0)'
My URL returns the following string:
first,second,third,fourth
And here is the iphone code with the book's working example commented out
#import "Simple_TableViewController.h"
#implementation Simple_TableViewController
#synthesize listData;
- (void)viewDidLoad
{
/*
//working code from book
NSArray *array = [[NSArray alloc] initWithObjects:#"Sleepy", #"Sneezy", #"Bashful", #"Bashful", #"Happy",
#"Doc", #"Grumpy", #"Thorin", #"Dorin", #"Norin", #"Ori", #"Balin", #"Dwalin", #"Fili", #"Kili", #"Oin",
#"Gloin", #"Bifur", #"Bofur", #"Bombur", nil];
self.listData = array;
[array release];
*/
//code from interwebz that crashes
NSString *urlstr = [[NSString alloc] initWithFormat:#"http://www.mysite.com/folder/iphone-test.php"];
NSURL *url = [[NSURL alloc] initWithString:urlstr];
NSString *ans = [NSString stringWithContentsOfURL:url];
NSArray *listItems = [ans componentsSeparatedByString:#","];
self.listData = listItems;
[urlstr release];
[url release];
[ans release];
[listItems release];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.listData = nil;
[super viewDidUnload];
}
- (void)dealloc
{
[listData release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
#end
YOu are overreleasing listItems as well as ans, that is probably your problem...WHen you dont do an alloc or retain (usually) the objects returned are autoreleased, therefore you dont need to release them. [NSString ...] returns an auto released string and so does the call [ans componentsSeparatedByString:#","]...hope that helps