-(id)init {
if (self = [super init]) {
self.name = [[NSString alloc] init];
self.type = [[NSString alloc] init];
self.phoneNumber = [[NSString alloc]init];
self.webAddress = [[NSString alloc] init];
NSMutableArray *pricesArray = [[NSMutableArray alloc] init];
NSMutableArray *poolsArray = [[NSMutableArray alloc] init];
self.prices = pricesArray;
self.pools = poolsArray;
[pricesArray release];
[poolsArray release];
//Create the address dictionaries
NSMutableDictionary *addressItems = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"", KAddressStreet1Key, #"", KAddressStreet2Key, #"", KAddressBoroughKey, #"", KAddressCityKey, #"", KAddressCountyKey, #"", KAddressPostCodeKey, #"" ,KAddressCountryKey, nil];
//Add dictionary to the array to contain address values
self.address = addressItems;
[addressItems release];
}
return self;
}
I'm currently doing a massive round of debugging thanks to EXC_BAD_ACCESS errors.. grr.
Does the code above seem fine and logical for a class init method? Basically I'm getting the EXC_BAD_ACCESS errors when I release both the pools (mutable array and the dictionary).
How are your properties declared? If they are not declared with retain then most of your objects will be deallocated at the end of this method.
You're leaking objects with each allocation for the string properties. Other than that, I don't notice anything wrong. How are the AddressXKeys defined?
Related
- (id)init {
if (self == [super init]) {
entries = [[NSMutableArray alloc] init];
NSString *file = [[NSBundle mainBundle] pathForResource:#"qanda" ofType:#"db"];
sqlite3 *database = NULL;
if (sqlite3_open([file UTF8String], &database) == SQLITE_OK) {
sqlite3_exec(database, "select * from qanda order by question", LoadEntriesCallback, entries, NULL);
}
sqlite3_close(database);
}
return self;
}
leak near entries object: instance variable used while 'self' is not set to the result of [ super of self[init ...]]
leak near self: returning while 'self' is not set to the result of [ super of self[init ...]]
You should have
self = [super init];
not
self == [super init];
The most common pattern to use is:
self = [super init];
if (self) {
// Initialisation code
}
return self;
In your example you are not assigning the result of [super init] to anything and it is left hanging, hence the leak and the message.
If you want to release entries as per the question in you title:
entries = [[[NSMutableArray alloc] init] autorelease];
or
entries = [[NSMutableArray alloc] init];
and
[entries release];
Before the return or in your dealloc.
You can release entries by replacing :
entries = [[NSMutableArray alloc] init];
with :
entries = [[[NSMutableArray alloc] init] autorelease];
But i think the question should be : is this a good way of getting the contents from the db and frankly i think your code would be better if you moved the reading content from the db part to a loadData method.
You should autorelease it while creating.
entries = [[[NSMutableArray alloc] init] autorelease];
Try replacing
entries = [[NSMutableArray alloc] init];
with
self.entries = [[[NSMutableArray alloc] init]autorelease];
and replacing
sqlite3_exec(database, "select * from qanda order by question", LoadEntriesCallback, entries, NULL);
with
sqlite3_exec(database, "select * from qanda order by question", LoadEntriesCallback, self.entries, NULL);
// Configure the cell.
cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row] objectForKey:#"Name"];
return cell;
The above code is generating this exception. What could be causing this and how can I fix it?
My Understand from Your question
You have array of drinks like
Drink *d1 = [[Drink alloc] init]
d1.name = #"Drink1";
d1.price = [NSNumber numberWithFloat:25.0];
Drink *d2 = [[Drink alloc] init]
d2.name = #"Drink2";
d2.price = [NSNumber numberWithFloat:35.0];
OR
NSArray *values1 = [NSArray arrayWithObjects:#"Drink1",[NSNumber numberWithFloat:25.0], nil];
NSArray *keys1 = [NSArray arrayWithObjects:#"Name",#"price", nil];
NSDictionary *d1 = [[NSDictionary alloc] initWithObjects:values1 forKeys:keys1];
NSArray *values2 = [NSArray arrayWithObjects:#"Drink2",[NSNumber numberWithFloat:55.0], nil];
NSArray *keys2 = [NSArray arrayWithObjects:#"Name",#"price", nil];
NSDictionary *d2 = [[NSDictionary alloc] initWithObjects:values1 forKeys:keys1];
self.drinks = [NSArray arrayWithObjects:d1,d2, nil];
[d1 release];
[d2 release];
From the above case
cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row] objectForKey:#"Name"];
the above statement is correct
You are getting exception means, You are inserting the objects into drinks array, that supports Key Value Pairs data and that is String Data.
I hope you are having like this
self.drinks = [NSArray arrayWithObjects:#"Drink1",#"Drink2", nil];
In this above case you have to go with
cell.textLabel.text = [self.drinks objectAtIndex:indexPath.row];
first try to determine what object is self.drinks,
then you can go finer depending if is an array with dictionaries?
do a log
[self.drinks objectAtIndex:0]
what do you see?
Ok, so the issue is coming from trying to pull data from a sqlite DB and place it in an array for a scroll view display. Im using FM Database library to connect to sql database
The code is as follows:
NSMutableArray *data = [[NSMutableArray alloc] init];
FMResultSet *result = [[[StorageTank sharedStorageTank] DB]
executeQuery:#"SELECT * FROM table"];
while([result next])
{
NSArray *values = [[NSArray alloc] initWithObjects:
[[NSNumber alloc] initWithInt:[result intForColumn:#"id"]],
[[NSNumber alloc] initWithInt:[result intForColumn:#"count"]],
[[NSNumber alloc] initWithInt:[result intForColumn:#"required"]],
[result stringForColumn:#"image_portrait"],
[result stringForColumn:#"image_landscape"],
[[NSNumber alloc] initWithInt:[result intForColumn:#"end_date"]],
[[NSNumber alloc] initWithInt:[result intForColumn:#"active"]],
[result stringForColumn:#"merchant"], nil];
NSLog(#"%#", values);
NSArray *keys = [[NSArray alloc] initWithObjects: #"id",#"count",#"required",
#"image_portrait",#"image_landscape",
#"end_date",#"active",#"merchant",nil];
NSLog(#"%#", keys);
NSDictionary *row = [[NSDictionary alloc] initWithObjects: values forKeys: keys];
[data addObject: row];
}
NSArray *resultArray = [[NSArray alloc] init];
resultArray = data;
So, obviously from the code i've tested to make sure the values count is equal to the keys count... yet Im still getting this error:
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSPlaceholderDictionary initWithObjects:forKeys:]: number of objects (3) not equal to number of keys (8)'"
I can't understand for the life of me why the count would differ if when I print out the values array I see 8 values... which should match my 8 keys? and they are correct?
Any help/direction would be greatly appreciated!
Thanks,
Is the fourth item in your values array:
[result stringForColumn:#"image_portrait"]
returning nil? That's the value that tells -initWithObjects that the list is done.
I want to populate an array like this:
NSMutableArray *array = [self methodThatReturnsAnArray];
In the "methodThatReturnsAnArray"-method I create an array like this:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
When I'm finished populating "arrayInMethod" I'm returning the array and in order to prevent a memory leak I'm using:
return [arrayInMethod autorelease];
However the "array"-variable is never populated. When removing the "autorelease" it works fine though. What should I do in order to make sure that the returned object i released?
EDIT
+ (NSMutableArray *)buildInstants:(NSArray *)huntsArray {
NSMutableArray *goGetObjects = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [huntsArray count]; i++) {
NSDictionary *huntDict = [huntsArray objectAtIndex:i];
PHGoGet *goGet = [[PHGoGet alloc] init];
goGet.title = [huntDict objectForKey:#"title"];
goGet.description = [huntDict objectForKey:#"description"];
goGet.start = [huntDict objectForKey:#"start"];
goGet.end = [huntDict objectForKey:#"end"];
goGet.ident = [huntDict objectForKey:#"id"];
if ((CFNullRef)[huntDict objectForKey:#"image_url"] != kCFNull) {
goGet.imageURL = [huntDict objectForKey:#"image_url"];
} else {
goGet.imageURL = nil;
}
if ((CFNullRef)[huntDict objectForKey:#"icon_url"] != kCFNull) {
goGet.iconURL = [huntDict objectForKey:#"icon_url"];
} else {
goGet.iconURL = nil;
}
goGet.longitude = [huntDict objectForKey:#"lng"];
goGet.latitude = [huntDict objectForKey:#"lat"];
goGet.companyIdent = [huntDict objectForKey:#"company_id"];
[goGetObjects insertObject:goGet atIndex:i];
[goGet release];
}
return [[goGetObjects copy] autorelease];
}
Try using the convienence method for NSMutableArray... change:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
To...
NSMutableArray *arrayInMethod = [NSMutableArray array];
array will return an autoreleased object.
First of all, I recommend you not to return a NSMutableArray from any method. It's better to use NSArray for that to avoid some very difficult to debug problems. My proposition is:
You declare the mutable array and populate it:
NSMutableArray *arrayInMethod = [[[NSMutableArray alloc] init] autorelease];
Then you return an autoreleased copy:
return [[arrayInMethod copy] autorelease];
And finally, when you take the returned array, you make it mutable again (only if you need to change it):
NSMutableArray *array = [[self methodThatReturnsAnArray] mutableCopy];
When you're done with the array, you release it:
[array release];
It is really mind boggling to find out many differences between the iphone and the simulators. I spent several hours trying to figure out why my application ran on the simulator but crashed on my iphone device. It turns out the culprit is sortedArrayUsingDescriptors. Are there more get-you like this? Please share with me.
To share with you on the issue and the fixes:
Code crashed on iphone but not simulator
NSSortDescriptor* aDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
NSArray* anNsArray = [[NSArray alloc] init];
NSArray* aSortedNsArray = [[NSArray alloc] init];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:aDescriptor]];
The issue is on [NSArray arrayWithObject:aDescriptor];
The fixes are to create an Array to store it:
NSArray* descriptorArray = [[NSArray alloc] initWithObjects:countDescrp, nil];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:descriptorArray];
NSSortDescriptor* aDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
NSArray* anNsArray = [[NSArray alloc] init];
NSArray* aSortedNsArray = [[NSArray alloc] init];
aSortedNsArray = [anNsArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:aDescriptor]];
This is a wrong initialization mechanism, and if the code snippet is complete, your problem lies on the anNsArray object that's empty.
You also do not need to initialize the aSortedNsArray.
So it should be:
NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:NO] autorelease];
// Assume you return it as array of objects from a property or method
NSArray *array = [self objects];
NSArray *sortedArray = nil;
if ([array count] > 0) {
sortedArray = [array sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
}
// Then you check the sortedArray
if (sortedArray == nil || [sortedArray count] == 0)
[self somethingIsWrong];
arrayWithObject: (autoreleased) or initWithObject: (manual) is just a different way to allocate NSArray object. It won't cause crashes normally. Because what you care about is the sortedArray not retaining the descriptors array object.