Obviously the following in the main method should lead to a leak:
NSMutableArray *strings = [[NSMutableArray alloc] init];
[strings addObject:#"Hello"];
[strings addObject:#"Howdy"];
return 0;
and the clang LLVM reports the leak. However, working through the Hillegass book, I tried analyzing the following code, which again does not release the NSMutableArray object:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
NSCalendarDate *now = [[NSCalendarDate alloc] init];
for (int i=0; i < 3; i++) {
LotteryEntry *newEntry = [[LotteryEntry alloc] init];
NSCalendarDate *iweeksFromNow = [now dateByAddingYears:0
months:0
days:(i*7)
hours:0
minutes:0
seconds:0];
[newEntry setEntryDate:iweeksFromNow];
[array addObject:newEntry];
[newEntry release];
}
[now release];
for (LotteryEntry *entry in array) {
NSLog(#"%#", entry);
}
[pool drain];
return 0;
This time there was no leak reported. Am I missing something obvious?
I don't think you areāthe static analyzer's just missing it. array does end with a retain count of 1; if the line were
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
then the enclosing autorelease pool would take care of it, but as it stands the array's definitely still leaking.
I've asked this on the cfe-dev list and the answer is analysis in loops is halted at a given threshold (only 2 loop iterations are walked through).
If you change your exit condition (for (int i=0; i < 2; i++)) the static analyzer will signal the leak.
Related
I have no idea why, but my NSMutableArray 'items' will not take more than 5 elements.
Can someone please help? I'm following the Big Nerd Ranch iOS Programming book.
This code works fine:
NSMutableArray *items = [[NSMutableArray alloc] init];
for (int i = 5; i < 10; i++) {
BNRItem *p = [BNRItem randomItem];
[items addObject:p];
}
However if I change the initial value of i to 4 or less the program crashes when exiting the for loop:
NSMutableArray *items = [[NSMutableArray alloc] init];
for (int i = 4; i < 10; i++) {
BNRItem *p = [BNRItem randomItem];
[items addObject:p];
}
Error screenshot: http://db.tt/3CdueSYh
Change your
NSArray *randomNounList = [NSArray arrayWithObjects:#"Bear", #"Spork", "Mac", nil];
to:
NSArray *randomNounList = [NSArray arrayWithObjects:#"Bear", #"Spork", #"Mac", nil];
You forgot # before "Mac"
Hope it helps
In the screenshot you posted in your comments you are adding a C string, "Mac", to your randomNounList array. You need to make this an NSString with an # symbol.
I suspect the crash is occurring when this entry is randomly selected.
I'm surprised this compiled, I suspect you are ignoring some warnings.
I'm receiving an exc_bad_access somewhere in the code below. I don't understand where it is if anyone could shine any light on it? It's a method that takes in an NSMutableArray of dictionaries and sorts them by one of the elements in the dictionary. The memory leak is almost certainly in the bit with the block but I think i'm missing something fundamental in finding it...
-(NSMutableArray*)sortBicyclesByDistanceToDevice:(NSMutableArray*)inputArray{
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b){
NSNumber *first = [[a objectForKey:kDistanceFromDevice] objectForKey:kValue];
NSNumber *second = [[b objectForKey:kDistanceFromDevice] objectForKey:kValue];
return [first compare:second];}];
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
[arrayToHoldSorted release];
return [retVal autorelease];
}
Thanks
It looks like you assign retVal to an NSMutableArray through then reassign immediately after. The original alloced NSMutableArray will leak. That is:
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
Should be:
NSMutableArray *retVal = [arrayToHoldSorted mutableCopy];
Replace:
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
With:
NSMutableArray *retVal = [arrayToHoldSorted mutableCopy];
You are leaking the first value of retVal.
There's more than one in there!
This line:
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
Is a memory leak since you immediately reassign the pointer. It should be removed. Just declare your array on the next line:
NSArray* arrayToHoldSorted = [inputArray sortedArrayUsingComparator...
This method returns an autoreleased object, so you don't need to release it later on.
A similar pattern with the mutable array. You alloc/init, then overwrite with a new object, giving another leak. Again, remove the alloc/init line and just declare in the next line. mutableCopy gives you an implicitly retained object, so you do need to autorelease it.
You seem to be under the impression that alloc/init is needed every time you declare an object variable. This is not the case.
You allocate arrayToHoldSorted (1) - which you never use as you then get an NSArray back from sortedArrayUsingComparator(2). And then you release it afterwards(3) when you don't own it. You do the same trick for retVal, allocating a NSMutableArray - then overwriting your reference to it by getting a new NSMutableArray from [arrayToHoldSorted mutableCopy];
NSArray *arrayToHoldSorted = [[NSArray alloc] init]; .. // 1
arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b) ..... // 2
[arrayToHoldSorted release]; // 3
Just assign the return NSArray from sortedArrayUsingComparator to a reference...
NSArray* arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b) .....
I think the problem is that in this line:
return [retVal autorelease];
you release something that you have not retained. Also in this line:
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
you have an extra [, which does not help. But most importantly, you can use the static analyzer in XCode to diagnose this sort of bug, rather than pestering the good folk on StackOverflow.
Okay, so, I'm doing a simple lookup. I have an array of NSString objects and a string to search for in the array's elements.
It all seems to work up until I try to add a match to a new mutable array made to hold the search results. The stringHolder variable gets the string, and resultsCollectorArray even get the right number of new elements, but each element is empty and "out of range". Here's the method:
#implementation NSArray (checkForString)
-(NSMutableArray *) checkForString: (NSString *) matchSought
{
long unsigned numberofArrayElements;
long unsigned loop = 0;
NSRange searchResults;
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init];
id stringHolder;
numberofArrayElements = [self count];
while (loop < numberofArrayElements) {
searchResults.length = 0;
searchResults = [[self objectAtIndex: loop] rangeOfString: matchSought options:NSCaseInsensitiveSearch];
if (searchResults.length > 0) {
stringHolder = [self objectAtIndex: loop];
[resultCollectorArray addObject: stringHolder];
}
loop++;
}
return [resultCollectorArray autorelease];
}
Once we get back to the main portion of the program, I get an unrecognized selector sent to the mutable array that was supposed to receive the result of the method. Here's the main section:
#import <Foundation/Foundation.h>
#import "LookupInArray.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testString = [[NSString alloc] initWithString: #"ab"];
NSMutableString * resultString = [[NSString alloc] init];
NSArray * theArray = [[NSArray alloc] initWithObjects: ..., nil]; // Actual code has the objects
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSUInteger arrayCount = 0;
unsigned long loops = 0;
resultArray = [theArray checkForString: testString];
arrayCount = [resultArray count];
while (loops < arrayCount){
resultString = [resultArray objectAtIndex: loops]; // Here's where we get the unrecognized selector.
NSLog(#"%#", resultString);
loops++;
}
[pool drain]; // Also, I'll release the objects later. I just want to get what's above working first.
return 0;
}
I've searched the other answers (for hours now), but didn't seen anything that solved the issue.
Any and all help would be really appreciated.
And thanks beforehand.
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init]; is so incorrect. You are creating a mutable set and assigning it to a mutable array.
You are getting unrecognized selector because objectAtIndex: is not a valid selector for NSMutableSet. Make that statement,
NSMutableArray * resultCollectorArray = [[NSMutableArray alloc] init];
A Better way
NSArray * filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchString]];
You can directly filter the array using predicates. This way you do this in a single step. :)
I'm having some issues with my Arrays, I hoped anyone here can tell me what I'm doing wrong.
I have 3 arrays: tmpAnswersArray, localAnswersArray & finalAnswersArray.
I also have a method to shuffle a given array in the same class.
The first NSLog shows the count for the localAnswersArray is 6 (how it supposed to be).
The third NSLog shows the localAnswersArray count is 0, even though I didn't change anything in that array.
localAnswersArray = [[NSMutableArray alloc] init];
localAnswersArray = [self shuffleArray:tmpAnswersArray];
[tmpAnswersArray release];
NSLog(#"Shuffled localAnswersArray (count = %d) & removed tmpAnswersArray",[localAnswersArray count]);
finalAnswersArray = [[NSMutableArray alloc] init];
NSLog(#"init finalAnswersArray");
for (int arrayCount = 0; arrayCount < 6; arrayCount++) {
NSLog(#"TEST ---> %d",[localAnswersArray count]);
[finalAnswersArray addObject:[localAnswersArray objectAtIndex:arrayCount]];
}
Is the first line of this code also retains the array?
Do I have to retain it manually somehow?
Why is the array count drops to 0 all of a sudden?
Thanks for any help!
You need to review the Memory Management Guidelines.
localAnswersArray = [[NSMutableArray alloc] init];
localAnswersArray = [self shuffleArray:tmpAnswersArray];
You create an array (that you own), then immediately replace it with a different array.
And it would seem that your entire block of code could be replaced with this:
finalAnswersArray = [[self shuffleArray:tmpAnswersArray] mutableCopy];
I am getting memory leak in NSMutableArray allocation.. in
NSMutableArray *contactsArray =[[NSMutableArray alloc] init];
CODE:
+(NSMutableArray*)getContacts
{
addressBook = ABAddressBookCreate();
NSArray* peopleArray = (NSArray*) ABAddressBookCopyArrayOfAllPeople(addressBook);
int noOfPeople = [peopleArray count];
NSMutableArray *contactsArray =[[NSMutableArray alloc] init];
for ( int i = 0; i < noOfPeople; i++)
{
ABRecordRef person = [peopleArray objectAtIndex:i];
ABRecordID personId = ABRecordGetRecordID(person);
NSString* personIdStr = [NSString stringWithFormat:#"%d", personId];
ContactDTO* contactDTO = [AddressBookUtil getContactDTOForId:personIdStr];
[contactsArray addObject:contactDTO];
}
[peopleArray release];
return contactsArray;
}
It is standard procedure that objects returned from methods (in your case, contactsArray) are autoreleased before returning.
You could either return [contactsArray autorelease]; or create it already autoreleased with [NSMutableArray arrayWithCapacity:noOfPeople]
You need to release contactsArray manually somewhere, because it does not define autorelease.