Retain count and memory management

I have prepared an example to easier describe what I am want to ask:


@interface ViewController ()

@end

@implementation ViewController {
  UIColor *_color;
}

- (void)viewDidLoad {
  [super viewDidLoad];
   
  [self getStaticVC];
   
  __block CFTypeRef test1;
  __block CFTypeRef test2;
  __block CFTypeRef test3;
  @autoreleasepool {
    test1 = [self getVC];
    test2 = [self getVC];
    test3 = [self getVC];
     
    NSLog(@"Test1: %lld", CFGetRetainCount(test1));
    NSLog(@"Test2: %lld", CFGetRetainCount(test2));
    NSLog(@"Test3: %lld", CFGetRetainCount(test3));
  }
}

- (UIViewController *)getStaticVC
{
  static UIViewController *vc;
  if (!vc) {
    vc = [UIViewController new];
  }
  return vc;
}

- (CFTypeRef)getVC
{
  return (__bridge CFTypeRef)[self getStaticVC];
}

@end

For this code above, if I will run it, it will print always that retain count is 4, but if I will change implementation of the method getVC to this:

- (CFTypeRef)getVC
{
  UIViewController *temp = [self getStaticVC];
  return (__bridge CFTypeRef)temp;
}

Code will always print retain count as 1.

My guess it is related to reference storage qualifier that is assigned to returned values from this methods. For value returned from getVC there are no storage qualifier, cos it is a void *, so I guess when we assigning to UIViewController *temp it likely mean that we are getting __strong local variable that is deallocated right after getVC finish, but for my first example, it seems like getVC return an __autoreleasing reference, otherwise I have no idea why reference count is growing ?

These days looking at retain counts is mostly counter productive, at least in my experience. With ARC the compiler inserts retains, releases, and autoreleases at its own discretion, and it’s not always easy to understand its rationale.

In this case I suspect that the compiler is inserting a retain / autorelease pair, so the ref count is growing on each -getVC but that’ll eventually get cleaned up when the autorelease pool drains.

Note If you’re not familiar with autorelease pools, see the discussion in Objective-C Memory Management for Swift Programmers.

Rather than looking at retain counts, I recommend that you instead look for leaks and retain cycles. That is, run your app and see if anything leaks or if there are objects that aren’t being cleaned up properly.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Retain count and memory management
 
 
Q