Memory Leak Field Variable - iphone

I do not undserstand why I cannot simply add [sortedArray release]; at the end of this method. Everytime I do, it crashes.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSString *workoutName = [event.assignedWorkout valueForKey:#"name"];
self.title = workoutName ;
NSMutableArray *sortedArray = [[NSMutableArray alloc]init];
// Sort ExerciseArray
int y = 0;
int x= 0;
do{
if ([[[exerciseArray objectAtIndex:y] index]intValue] == x){
[sortedArray addObject:[exerciseArray objectAtIndex:y] ];
x++;
}
if (y<[exerciseArray count]-1){
y++;
}else {
y=0;
}
}
while(x <= [exerciseArray count]-1);
exerciseArray = sortedArray;
[self.tableView reloadData];
}
If anyone can point me in the right direction or refer me to some documentation, it would be very much appreciated.

You are assigning the array to the exerciseArray variable and then you are releasing the array. The next time you try to access the exerciseArray variable, the array will be gone, because assigning it to the exerciseArray variable doesn't increase its retain count.
The array object's retain count is 1 when you first call alloc. When you assign it to exerciseArray, its retain value is still 1. Then, when you release it, its retain count drops to 0 and you can't expect to access the array again.
You should either not release it (my preference), or else explicitly retain it by calling:
[exerciseArray release];
exerciseArray = [sortedArray retain];
[sortedArray release];
Note the order of those two messages. The first line releases any existing object pointed to by the exerciseArray variable. The second line raises the new array's retain count to 2, and the second then drops it to 1, so the array is still retained. If you release sortedArray before assigning the new array to the exerciseArray variable, the retain count becomes 0 and you will lose it before you can assign it to the new variable.

You probably wanted to do:
[exerciseArray release];
exerciseArray = sortedArray;
[self.tableView reloadData];
BTW, you can sort an Array using a block with sortedArrayUsingComparator.

Related

Array1 is added into Array2 then Array1 is cleared and suddenly disappears from Array2

I have this curious thinf happening here where tempArray is supposed to be added to the masterArray each time the if statement occurs. (The if statement works perfectly and gets triggered when it should.)
I also need to clear the temp array each time it does.
My final result should then be a masterarray which contains each array it has added.(meaning all the temp arrays that I have added throughout the for loop)
Instead, it only keeps adding the tempArray to the MasterArray at index 0 every single time.
Code:
- (void)alpabetize:(NSArray *)arr {
self.tempArray = [[NSMutableArray alloc] init];
self.masterArray = [[NSMutableArray alloc] init];
for (int i = 0; i<[arr count]; i++) {
NSString *currentString = [NSString stringWithFormat:#"%#", [[[arr objectAtIndex:i] valueForKey:#"first_name"] substringToIndex:1]];
NSString *nextString = [NSString stringWithFormat:#"%#", [[[arr objectAtIndex:(i+1)] valueForKey:#"first_name"] substringToIndex:1]];
[self.tempArray addObject:[arr objectAtIndex:i]];
if (![currentString isEqualToString:nextString]) {
[self.masterArray addObject:tempArray];
[self.tempArray removeAllObjects];
}
}
}
If you remove all objects from the original array previously added to some other array. Does this also clear the other array? This makes no sense to me. There must be something wrong in my code. Can somebody help me spot my error?
Thank you for your time!
Use
[self.masterArray addObject:[tempArray copy]]; // retained copy of array
or
[self.masterArray addObject:[NSArray arrayWithArray:tempArray]]; // auto released copy of array
instead of
[self.masterArray addObject:tempArray];
In your code you are adding the reference of the same array which you are clearing in next statement.
[self.masterArray addObjectsFromArray:tempArray];
[tempArray removeAllObjects];
Are you sure you want to release the self.tempArray inside the loop? Once it enters your IF-condition the the array will be nil and you'll have no use of it unless you call the this method again. Try releasing the self.tempArray after the for loop.

retaincount will be increased after copy an array

I am developing one application. In that I am performing search operation once.
see my search method:
-(void)searchData
{
//[A release];
B =[A copy];
[A release];
NSLog(#"A retain count %i",[A retainCount]);
NSLog(#"B retain count %i",[B retainCount]);
C = [[NSMutableArray alloc]init];
[C removeAllObjects];
for (int i=0; i<[B count]; i++) {
DataBaseFields *data = [B objectAtIndex:i];
NSRange range= [data.DBtitle rangeOfString:searchEvents.text options:NSCaseInsensitiveSearch];
if (range.length>0) {
[C addObject:data];
}
}
NSLog(#"shouldChangeTextInRange text is %#",searchEvents.text);
A = [C copy];
NSLog(#"A retain count %i",[A retainCount]);
NSLog(#"C retain count %i",[C retainCount]);
[tableView1 reloadData];
}
In this code A,B,C are three NSMutableArrays. I am not allocating the memory and didn't write properties for that arrays. In this if search operation display any data then Array A shows the retainCount at last 1. If there is no result then Array A shows the retainCount at last 32 or 46. So please tell me how to solve this one.
retainCount is useless. Don't call it.
Beyond being generically meaningless, you are seeing odd retain counts in this code because, as an implementation detail, the frameworks are likely calling retain/autorelease on the objects. Since the retain count doesn't reflect the # of times an object has been autoreleased, the retain count is extra meaningless in your code.
Note also that the removeAllObjects in this is unnecessary.
C = [[NSMutableArray alloc]init];
[C removeAllObjects];
Better yet: Since it appears that you are relatively new to iOS development, turn on ARC and be done with all those retain/release/autorelease calls entirely.

EXC_BAD_ACCESS error in during fetching data from custome objects

I had stored custom objects data in Array. I am fetching data from Array of custom objects in a function. when I am calling function for first time it is working good but When I am calling it again and again I am getting EXC_BAD_ACCESS.
Here is function details.
-(void) facebookDisplayFunction:(int)atIndex {
FacebookWallData *wall = (FacebookWallData *)[facebook_wallDataArray objectAtIndex:atIndex];
NSString *friendID= wall.actor_id;
NSString *linkFetch= wall.permalink;
NSString* postID=wall.postId;
NSNumber *countNumber;
NSString *friendName=#"";
NSString* profileThumImage=#"";
for(int i=0; i< [facebook_LikesArray count];i++) {
FacebookLikes* countValues=[[FacebookLikes alloc]init];
countValues=[facebook_LikesArray objectAtIndex:i];
// NSLog(#" postId_wall %# LikePostId = %#",postID,countValues.PostID);
if([postID isEqualToString:countValues.PostID]) {
countNumber=countValues.Count;
if(countNumber>0)
friendID=countValues.Friends;
[countValues release];
break;
}
[countValues release];
}
for(int i=0;i< [facebook_FreindsArray count];i++) {
FacebookFreinds* friendsRecord=[[FacebookFreinds alloc]init];
friendsRecord=[facebook_FreindsArray objectAtIndex:i];
if([friendID isEqualToString:friendsRecord.UID]) {
friendName=friendsRecord.name;
profileThumImage=friendsRecord.pic_smal;
[friendsRecord release];
break;
}
[friendsRecord release];
}
// Adding values in table //
[imageData addObject:#"facebook.png"];
[tableList addObject:wall.messages];
[profileUserName addObject:friendName];
[linksOfFacebookData addObject:linkFetch];
[RetweetAndLikeData addObject:#"5"];
[favedProfileThumb addObject:profileThumImage];
[twitterPostID addObject:#""];
[eachPostUID addObject:friendID];
[wall release];
}
And here I am calling function.
[self facebookDisplayFunction:0];
[self facebookDisplayFunction:0]; // EXC_BAD_ACCESS error here.
Why are you allocating an object like this FacebookLikes* countValues=[[FacebookLikes alloc]init] and then assigning to this same variable the instance inside the array with this code countValues=[facebook_LikesArray objectAtIndex:i] and later on you release it with this [countValues release]? You don't know what you are doing.
Try changing this:
FacebookLikes* countValues=[[FacebookLikes alloc]init];
countValues=[facebook_LikesArray objectAtIndex:i];
to this
FacebookLikes* countValues = [facebook_LikesArray objectAtIndex:i];
and remove all occurrences of [countValues release]. Do the same for the friendsRecord in the second for-loop. Also, what is the [wall release]? Remove it!
You should not allocate any of these objects because you are actually obtaining them from that array, and not creating a new instance. That just creates a leak in your code. You should not release any of these objects because they are retained by the array, and it is responsible for releasing them whenever they are removed from the array or after the array is destroyed/deallocated. Please, rtfm
If you get the error on the line:
[self facebookDisplayFunction:0];
it seems to me that most likely the object pointed by self has been deallocated. So, the problem would not be in facebookDisplayFunction...
Could you review how you create the object pointed by self, or post the code if you need more help?

how do I create fresh NSMutableArray?

I have an NSMutableArray which only lasts during the session.
Currently I create it like this
NSMutableArray *temp = [[NSMutableArray alloc] initWithCapacity:10];
[self setScoreArray:temp];
[temp release];
Problem is when I go to check each index I'm getting an array outofbounds error
NSNumber *previousScore = [[self scoreArray] objectAtIndex:[self quizNum]];
if ( previousScore != nil )
{
[self clearQuizBtns];
NSInteger previousScoreValue = [previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
I've read in other posts that initWithCapacity doesn't actually create the array. So what can I populate the array with initially?
Thanks in advance.
Two ways:
first: to initiate array with default values of NSNull class
NSMutableArray *temp = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0 ; i < 10 ; i++)
{
[temp insertObject:[NSNull null] atIndex:i];
}
[self setScoreArray:temp];
[temp release];
and then to check: if object is kind of NSNull class means it was a never set before
id previousScore = [[self scoreArray] objectAtIndex:[self quizNum]];
if (![previousScore isKindOfClass:[NSNull class]])
{
[self clearQuizBtns];
NSInteger previousScoreValue = [(NSNumber *)previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
second: store scores in NSMutableDictionary and use NSNumber's as keys
// scoreDictionary property of NSMutableDictionary class must be declared in self
NSNumber *previousScore = [self.scoreDictionary objectForKey:[NSNumber numberWithInt:[self quizNum]]];
if (previousScore != nil)
{
[self clearQuizBtns];
NSInteger previousScoreValue = [previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
NSArray does not support "holes". The capacity is just a hint to the initializer.
You could either fill the array with placeholder objects or, more typically, change your algorithm to either fully prepopulate the array or to lazy load it linearly.
Your problem seems to be that you're never actually setting any score in the score array.. are you? NSArrays have an actual count of items in them, and accessing an index beyond that count will blow up, as you've seen. If there will only ever be a fixed (small) number of scores, like 10, then you could set them all initially to something default like:
for (int i = 0; i < 10; i++) {
[temp addObject:[NSNumber numberWithInt:0]];
}
P.S. -initWithCapacity does "create the array", it just doesn't create any objects in the array. The capacity is a hint only.
Using the arrayWithObject: or arrayWithObjects: methods can provide an array with pre-populated values.
One cool thing about NSMutableArrays is that you can just do an "init" and the array will handle adding and removing objects on the fly. Remember that you generally addObject: or removeObjectAtIndex: when dealing with mutable arrays.

how to detect if an array isnt empty?

I am trying to detect if an array isn't empty in order to be able to do a certain call.
I tried using if (![array ==nil]) however that doesn't compile.
I'm sure there is a really easy explanation to this.
Update
If array is empty I want to do this:
array = [[NSMutableArray alloc]init];
If it has an object I want to do this:
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
If you declared it but did not assign anything to it at all:
NSMutableArray *array;
Then the array will be nil, meaning it isn't there at all so you can't say if it's empty or not, so you can't check anything.
If you did assign something to it, and you want to find out if the existing array is empty or not, that would depend on how you created it first.
If the array was assigned from some convenience method, it's autoreleased, so just do this:
if ([array count] == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
If the array was assigned from an init or copy method, or it was retained previously, store the count in a temporary variable, release the array and use the temporary variable to decide what to do:
NSInteger count = [array count];
[array release];
if (count == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
In your case I'd always use without differentation
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
and set the default value in the user defaults to an empty array right away at program start before accessing the defaults (from Apple's example):
+ (void)initialize{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:[NSArray array] forKey:#"MyFavorites"];
[defaults registerDefaults:appDefaults];
}
See Apple's doc on this.
Supposing you are talking about NSArray, if myArray has not been properly alloced+initialized (what you are trying to check) its reference will be nil, so you can do:
if(myArray) //or even if(myArray != nil) since myArray will be a pointer
{
//properly inizialized
}
else
{
//not properly inited
}
If it's been inited on the other hand, you can test its emptiness by checking the count property which returns the number of elements it contains
if([myArray > 0])
//there is at least one element
}
else
{
//no elements
}
you can use count function of NSArray. it will work on NSMutableArray too....
syntext will be,
int ct=[array count];
ct will have number of items in array.
if it us empty it will be Zero