retaincount will be increased after copy an array - iphone

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.

Related

Beginner memory management

I need to know if the retaincount of objects should always be 0 if i want to have a good memory management in my code. I got the following code from a book. and there's a statement NSLog called after release = 2, So should i have to release it 2 more times so that the retaincount will be 0 ?
#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSValue.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSNumber *myInt = [NSNumber numberWithInteger: 100];
NSNumber *myInt2;
NSMutableArray *myArr = [NSMutableArray array];
NSLog (#”myInt retain count = %lx”,
(unsigned long) [myInt retainCount]);
[myArr addObject: myInt];
NSLog (#”after adding to array = %lx”,
(unsigned long) [myInt retainCount]);
myInt2 = myInt;
NSLog (#”after asssignment to myInt2 = %lx”,
(unsigned long) [myInt retainCount]);
[myInt retain];
NSLog (#”myInt after retain = %lx”,
(unsigned long) [myInt retainCount]);
NSLog (#”myInt2 after retain = %lx”,
(unsigned long) [myInt2 retainCount]);
[myInt release];
NSLog (#”after release = %lx”,
(unsigned long) [myInt retainCount]);
[myArr removeObjectAtIndex: 0];
NSLog (#”after removal from array = %lx”,
(unsigned long) [myInt retainCount]);
[pool drain];
return 0;
}
Program Output
myInt retain count = 1
after adding to array = 2
after asssignment to myInt2 = 2
myInt after retain = 3
myInt2 after retain = 3
after release = 2
after removal from array = 1
UPDATE
The following code was taken from the Apples memory management document. They have retained a NSNumber object and its never been released, is this OK ?
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
You shouldn't be worried about the retain count of your objects, especially because the the NSArray or other objects might retain and then only later release things you pass to them. I'd strongly suggest focusing instead on Objective-C and Cocoa's memory management rules, which ensure that things are cleaned up when needed.
This is not to take away from existing answers, but to address your edit (Which, by the way, should REALLY be a separate question.):
They have retained a NSNumber object and its never been released, is this OK ?
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
Well it wouldn't be, if that was what they did.
You are confusing pointers with objects. Do you see the (NSNumber *) just before newCount. That '*' means that newCount is a pointer to an NSNumber object. Allow me to translate.
[newCount retain];
Retain the object referred to by the pointer 'newCount'.
[_count release];
Send a release message to the object currently referred to by the '_count' pointer.
_count = newCount;
Make the pointer '_count' refer to the object that is referred to by the pointer 'newCount'
Think of it like this, if you have a car you likely just call it myCar. When you say myCar you mean your car, the car you own. Let's say you buy a new car for a while you will call it newCar so that you can tell the difference. So you take ownership of your new car [newCar retain], and for a brief moment you own two cars. Now you sell your old car, which you still call myCar, [myCar release](very sad). But now when you say myCar you mean your newCar myCar = newCar. You no longer own your old car. And now your newCar is just myCar and you own, retain, that one. When you die, dealloc, your car will be sold,[myCar release].

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?

Memory Leak Field Variable

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.

iPhone Application crashes

When I do the following my application crashes and I get an error (terminate called after throwing an instance of 'NSException') whenever i run the simulation:
for (...)
[Array1 replaceObjectAtIndex:i withObject: [NSString stringWithFormat:#" Trip %i",i+1]]
OK after writing the problem I have found that the error is "0 is beyond bounds for empty array".
You really really really need to post the type of exception and your code to give us a reasonable chance of solving your problem. However, I'm going to taker a shot at it anyway.
My guess is your code looks something like this:
Array1 = [[NSMutableArray alloc] initWithCapacity: someNumber];
for (i = 0 ; i < someNumber ; ++i)
{
[Array1 replaceObjectAtIndex:i withObject: [NSString stringWithFormat:#" Trip %i",i+1]];
}
All arrays start out with 0 objects in them even if you use -initWithCapacity:. That method only provides a hint to the runtime that the array will grow to the specified size at some point. You need to use -addObject:.
Edit
Yep, from your edit, I'm sure I am right. The array has started out empty and you are trying to replace the object at index 0 which isn't there yet.
The code above should be changed as follows:
array1 = [[NSMutableArray alloc] initWithCapacity: someNumber]; // fixed naming convention too :-)
for (i = 0 ; i < someNumber ; ++i)
{
[array1 addObject: [NSString stringWithFormat:#" Trip %i",i+1]];
}
-addObject: adds the new objects to the end of the array.
If you want something that looks more like a C or Java array, you can prefill the array with NSNull objects
array1 = [[NSMutableArray alloc] initWithCapacity: 6]; // fixed naming convention too :-)
for (i = 0 ; i < 6 ; ++i)
{
[array1 addObject: [NSNull null]];
}
// Now the following will work
[array1 replaceObjectAtIndex: 4 withObject: #"foo"];
if you are using replaceObjectAtIndex method with NSArray array type object, there is possibility of getting exception (crashed).
Use NSMutableArray for managing a modifiable array of objects.
Although replaceObjectAtIndex can also be raised the following Exception for Object and Index
Index: Raises an NSRangeException if index is beyond the end of the array.
Object: Raises an NSInvalidArgumentException if Object you are passing is nil.
Ok, here is a guess (I can't do better without more information):
You cannot change an object you are iterating over.
(Bad) Example:
for (NSObject *obj in Array1){
[Array1 replaceObjectAtIndex:i withObject: [NSString stringWithFormat:#" Trip %i",i+1]]
}

Why is the retainCount is 0 instead of 1?

Here is the code. I have tested with NSString, and it return -1. But for NSMutableArray is 0 instead.
NSMutableArray *items = [[NSMutableArray alloc] init];
for(int i=0;i<10;i++)
{
[items addObject:[Possession randomPossession]];
}
/*for(int i=0;i<[items count];i++)
{
NSLog(#"%#", [items objectAtIndex:i]);
}*/
//Using Fast Enumeration
/*for(items in items)
{
NSLog(#"%#", items);
}*/
NSLog(#"%d", [items retainCount]);
I made mistake by using array in iteration. The correct one should be like this.
//Using Fast Enumeration
for(Possession *item in items)
{
NSLog(#"%#", item);
}
And the retainCount is back to normal as expected 1.
A) You should never look at retainCount, even for debugging. It's an internal implementation detail that can provide confusing results.
B) This:
for(items in items)
is almost certainly not what you mean -- you're using the array object ("items") as the iterator too! Something like:
for(Possession *item in items)
would make more sense.
update:
You might want to look at some of the examples in Apple's documentation on fast enumeration. You really want to have a separate variable that acts as your loop iterator. What you're doing (for(items in items)) sets items to each object in the array in turn, and when you exit the loop, items will be nil!