-3

I'm trying to understand the difference between the memory management of the following four cases:

@implementation ABC

-(void) fun1 
{
   ObjectA * obj1 = [[ObjectA alloc] init];
   ObjectA * obj2 = obj1;
}

-(void) fun2 
{
   ObjectA * obj1 = [[ObjectA alloc] init];
   ObjectA * obj2 = [obj1 retain];
}

-(void) fun3 
{
   ObjectA * obj1 = [[ObjectA alloc] init];
   ObjectA * obj2 = [obj1 copy];
}

-(void) fun4
{
   ObjectA * obj1 = [[ObjectA alloc] init];
   ObjectA * obj2 = [obj1 mutableCopy];
}

@end

I consulted this question, but I still don't clearly understand the differences between each of the above. Could someone explain what each does, and why they differ?

Community
  • 1
  • 1
Nirav Gadhiya
  • 6,342
  • 2
  • 37
  • 76
  • 5
    Have you looked at the documentation? – nhgrif Oct 14 '13 at 13:57
  • 2
    Turn on ARC and they are all the same (once you remove the stuff that is no longer needed)... As @nhgrif implied, this is well documented in the documentation included with the dev tools. – bbum Oct 14 '13 at 13:58
  • i know that with ARC all of these are same but i want to know the exact difference between these all... – Nirav Gadhiya Oct 14 '13 at 14:44

2 Answers2

6

I'm inferring from the presence of retain, that you're employing MRR (manual retain and release). In MRR, this code results in:

@implementation ABC

-(void) fun1 
{
   ObjectA * obj1 = [[ObjectA alloc] init];  // retainCount = +1
   ObjectA * obj2 = obj1;                    // unchanged

   // you have one instance of `ObjectA` with a retain count of +1
   // both `obj1` and `obj2` point to the same single instance
}

-(void) fun2 
{
   ObjectA * obj1 = [[ObjectA alloc] init];  // retainCount = +1
   ObjectA * obj2 = [obj1 retain];           // retainCount = +2

   // you have one instance of `ObjectA` with a retain count of +2
   // both `obj1` and `obj2` point to the same single instance
}

-(void) fun3 
{
   ObjectA * obj1 = [[ObjectA alloc] init];  // retainCount of `obj1` object = +1
   ObjectA * obj2 = [obj1 copy];             // retainCount of `obj2` object = +1

   // you have two instances of `ObjectA`, each with a retain count of +1
   // `obj1` points to one instance and `obj2` point to the other
}

-(void) fun4
{
   ObjectA * obj1 = [[ObjectA alloc] init];  // retainCount of `obj1` object = +1
   ObjectA * obj2 = [obj1 mutableCopy];      // retainCount of `obj2` object = +1

   // you have two instances of `ObjectA`, each with a retain count of +1
   // `obj1` points to one instance
   // `obj2` points to another instance, which is mutable copy of the `obj1` instance
}

@end

Clearly, in all of these cases, in MRR, if you don't do something with the ObjectA instances by the end of the method, you'll be leaking (because you're abandoning the last known reference to these objects). If using ARC, the necessary clean up is performed.

By the way, in the future, you should examine the results yourself. For example, if you added these diagnostic statements to the end of each method, you'd clearly see what's going on:

NSLog(@"%s: [obj1 (%p) retainCount] = %d", __FUNCTION__, obj1, [obj1 retainCount]);
NSLog(@"%s: [obj2 (%p) retainCount] = %d", __FUNCTION__, obj2, [obj2 retainCount]);

That displays the address of the object to which the variable points, as well as the object's current retainCount. Needless to say, you shouldn't be using retainCount in production code, but it's useful solely for diagnostic purposes.

By way, while it's good that you're trying to understand the memory management, I would suggest that you seriously consider using automatic reference counting (ARC). It makes memory management much easier (no retain, release or retainCount). And if you're determined to stick with manual retain and release (MRR), then make sure you run your code through the static analyzer ("Analyze" on Xcode's "Product" menu), as it's pretty decent in identifying the sort of problems that plague MRR code.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Reminder that http://www.whentouseretaincount.com exists. No, not an indictment of the above answer. Anything but; this is a fantastic answer. – bbum Oct 14 '13 at 16:15
  • @bbum Agreed, `retainCount` should only be used for diagnostic purposes in MRR, not for any functional purposes. It's largely moot now, anyways, because it's not even available in ARC (other than in Instruments). – Rob Oct 14 '13 at 16:23
1

Just a simple difference whenever you write retain it will increment the count and whenever you write copy it will make reference and does not increment the count for example let say:-

  NSObject *ret=[obj1 retain];
  It will increment the count by 1in      
  memory(count will become 2)

  NSObject *cop=[obj1 copy];
 It will not increment the count here count will    
  be 1only it just create the new reference in 
  memory. (count will remain same 1 only)
Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
  • 1
    I'd suggest you toss this code into a simple project and test it. The results will be surprising, I'd bet. – bbum Oct 14 '13 at 16:16
  • Ok can you please explain what you want to describe ?? – Hussain Shabbir Oct 14 '13 at 16:19
  • 1
    @hussainShabbir Your general observation is largely correct, but your choice to illustrate it with `NSString` is unfortunate, because that's a [class cluster](https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html), and thus does not report retain counts as you suggest. Like bbum suggested, try your code out, and look at the `retainCount` values. – Rob Oct 14 '13 at 16:36
  • @hussainShabbir That and making claims about absolute retain count are generally not very useful; retain count cannot reflect autorelease state nor can you know the implementation details of the framework that may influence the retain count in surprising ways. – bbum Oct 14 '13 at 16:59
  • 1
    I have updated the same, please have a look on it and correct me if i am wrong – Hussain Shabbir Oct 14 '13 at 17:04