iOS &
Memory Management
            Basics
    Cameron Barrie - @whalec
iOS &
Memory Management
   Memory Management Programming Guide:
   https://developer.apple.com/iphone/library/
documentation/Cocoa/Conceptual/MemoryMgmt/
               MemoryMgmt.html
iOS Memory Management


   alloc/copy/retain/release/autorelease

  Program received signal: "EXC_BAD_ACCESS".
iOS Memory Management
iOS Memory Management
 ObjectiveC objects contain a ‘count’ of how many
  other objects are currently holding onto them.

 You increment that count with the retain message.
You decrement that count with the release message.

             When that count hits 0.
      The object is deallocated from memory
iOS Memory Management
Memory Management Rules:
iOS Memory Management
Memory Management Rules:
  1. You only release objects you own:
iOS Memory Management
Memory Management Rules:
  1. You only release objects you own:
  [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]
iOS Memory Management
 Memory Management Rules:
     1. You only release objects you own:
     [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];
iOS Memory Management
 Memory Management Rules:
     1. You only release objects you own:
     [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];



     2. Or objects you take ownership of:
iOS Memory Management
 Memory Management Rules:
     1. You only release objects you own:
     [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];



     2. Or objects you take ownership of:

                 [[UIFont fontWithName:@"HoboStd" size:25] retain]
iOS Memory Management
 Memory Management Rules:
     1. You only release objects you own:
     [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];



     2. Or objects you take ownership of:

                 [[UIFont fontWithName:@"HoboStd" size:25] retain]




          Retaining an object simply increments an objects retainCount by 1.
iOS Memory Management
Releasing an object
  Release an object by sending it the release message
iOS Memory Management
 Releasing an object
     Release an object by sending it the release message

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];

[mutableTopLevelObjects release];
iOS Memory Management
 Releasing an object
     Release an object by sending it the release message

NSArray *topLevelObjects = [[NSBundle mainBundle]
                             loadNibNamed:@"UPLeaderboardViewCell"
                             owner:nil options:nil];
NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];

[mutableTopLevelObjects release];




                Releasing an object doesn’t remove it from memory.
                It simply decrements the objects retainCount by 1.
                When an objects retainCount is equal to 0.
                The object is deallocated by the runtime automatically.
iOS Memory Management
 Releasing an object
     Release an object by sending it the release message

NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];
[topLevelObjects retainCount]; // => 1
[topLevelObjects retain];
[topLevelObjects retainCount]; // => 2
[mutableTopLevelObjects release];
[topLevelObjects retainCount]; // => 1

[topLevelObjects release];
[topLevelObjects retainCount]; // => 0




                Releasing an object doesn’t remove it from memory.
                It simply decrements the objects retainCount by 1.
                When an objects retainCount is equal to 0.
                The object is deallocated by the runtime automatically.
iOS Memory Management
So what about the other objects?
iOS Memory Management
So what about the other objects?
    They’re what’s known as autorelease objects.
iOS Memory Management
 So what about the other objects?
        They’re what’s known as autorelease objects.

// This object will be automatically released at some point
// in the future when the autorelease pool is drained
NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1];
iOS Memory Management
 So what about the other objects?
        They’re what’s known as autorelease objects.

// This object will be automatically released at some point
// in the future when the autorelease pool is drained
NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1];




        You can mark your own objects as autorelease objects
iOS Memory Management
 So what about the other objects?
        They’re what’s known as autorelease objects.

// This object will be automatically released at some point
// in the future when the autorelease pool is drained
NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1];




        You can mark your own objects as autorelease objects
[topLevelObjects retainCount]; // => 1
[topLevelObjects autorelease];
[topLevelObjects retainCount]; // => 1 since it will be released later
iOS Memory Management
NSAutoreleasePool
    “Cocoa always expects there to be an autorelease pool available”
      - Memory Management Programming Guide: Autorelease Pools

    // main.m
    // The main entry point into the app sets up
    // an autorelease pool for us automatically
    int main(int argc, char *argv[])
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
        int retVal = UIApplicationMain(argc, argv, nil, nil);
        [pool release];
        return retVal;
    }
iOS Memory Management
Common mistakes
iOS Memory Management
Common mistakes
    // You need to mark zero for autorelease or release it
    - (void)reset {
        NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
        [self setCount:zero];
    }
iOS Memory Management
Common mistakes
    // You need to mark zero for autorelease or release it
    - (void)reset {
        NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
        [self setCount:zero];
    }



    // zero is an autorelease object already.
    // you haven't used alloc/copy anywhere
    // you are over releasing the zero object
    - (void)reset {
        NSNumber *zero = [NSNumber numberWithInteger:0];
        [self setCount:zero];
        [zero release];
    }
iOS Memory Management
Common confusion
   // Adding an object to a collection retains the object
   // It transfers ownership to the parent collection
   // Since alloc/copy was never called you don’t need
   // to release convenienceNumber
   NSMutableArray *array = [[NSMutableArray alloc] init];
   NSUInteger i = 0;
   for (i; i < 10; i++) {
       NSNumber *convenienceNumber = [NSNumber numberWithInteger:i];
       [array addObject:convenienceNumber];
   }
iOS Memory Management
Common confusion
   // Adding an object to a collection retains the object
   // It transfers ownership to the parent collection
   // You need to release allocedNumber here since you alloced it.
   NSMutableArray *array = [[NSMutableArray alloc] init];
   NSUInteger i = 0;
   for (i; i < 10; i++) {
       NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger: i];
       [array addObject:allocedNumber];
       [allocedNumber release];
   }
iOS Memory Management
Returning Objects from Methods
iOS Memory Management
Returning Objects from Methods
 // Correct - You don't own the string object so you should return it as such.
 - (NSString *)fullName {
     NSString *string = [NSString stringWithFormat:@"%@ %@",
                          self.firstName, self.lastName];
     return string;
 }
iOS Memory Management
Returning Objects from Methods
 // Correct - You don't own the string object so you should return it as such.
 - (NSString *)fullName {
     NSString *string = [NSString stringWithFormat:@"%@ %@",
                          self.firstName, self.lastName];
     return string;
 }

 // Incorrect - You're returning an object that has already been released.
 - (NSString *)fullName {
     NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
                                           self.firstName, self.lastName]
                                           release];
     return string;
 }
iOS Memory Management
Returning Objects from Methods
 // Correct - You don't own the string object so you should return it as such.
 - (NSString *)fullName {
     NSString *string = [NSString stringWithFormat:@"%@ %@",
                          self.firstName, self.lastName];
     return string;
 }

 // Incorrect - You're returning an object that has already been released.
 - (NSString *)fullName {
     NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
                                           self.firstName, self.lastName]
                                           release];
     return string;
 }

 // Correct - You've created an autorelease object.
 - (NSString *)fullName {
     NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
                                           self.firstName, self.lastName]
                                           autorelease];
     return string;
 }
iOS Memory Management
Accessor Method - @property/@synthesize
iOS Memory Management
Accessor Method - @property/@synthesize
 // MyClass.h
 @property(nonatomic, readwrite, retain) NSString *myString
iOS Memory Management
Accessor Method - @property/@synthesize
 // MyClass.h
 @property(nonatomic, readwrite, retain) NSString *myString


 // MyClass.m
 @synthesize myString = _myString;
 -(id)init
 {
     if ((self = [super init]))
     {
         self.myString = @"A string to be retained";
     }
     return self;
 }

 -(void)dealloc
 {
     [_myString release], _myString = nil;

     [super dealloc];
 }
iOS Memory Management
Accessor Method - @property/@synthesize

 // MyClass.h
 // Will retain the variable sent to it.
 @property(nonatomic, readwrite, retain) NSString *myString;

 // Will not retain the variable sent to it.
 @property(nonatomic, readwrite, assign) NSString *myWeakString;
iOS Memory Management
Accessor Method - @property/@synthesize
 // MyClass.m
 // Will retain the variable sent to it.
 @synthesize myString = _myString;

 // The @synthesize produces a setter/getter combo(readwrite)
 -(NSString *)myString
 {
     return _myString;
 }

 -(void)setMyString:(NSString *)myString
 {
     if (myString != _myString)
      {
         [_myString release];
         _myString = [myString retain];
     }
 }
iOS Memory Management
Accessor Method - @property/@synthesize

 // MyClass.m
 // Will not retain the variable sent to it.
 @synthesize myWeakString = _myWeakString;

 // The @synthesize produces a setter/getter combo(readwrite)
 -(NSString *)myWeakString
 {
   return _myWeakString;
 }

 -(void)setMyWeakString:(NSString *)myWeakString
 {
   _myWeakString = myWeakString;
 }
iOS Memory Management
Accessor Methods - @property/@synthesize
 // MyClass.m
 // By synthesizing in this way you are protecting your iVar so it can
 // only be accessed through the setter.
 // It also means you can pass the argument myString to methods.
 @synthesize myString = _myString;

 -(id)initWithMyString:(NSString *)myString
 {
     if ((self = [super init]))
     {
         self.myString = myString;
     }
     return self;
 }

 +(id)myClassWithMyString:(NSString *)myString
 {
     return [[self initWithMyString:myString] autorelease];
 }
iOS Memory Management
Accessor Methods - @property/@synthesize
 // MyClass.m
 // By synthesizing in this way you are protecting your iVar so it can
 // only be accessed through the setter.
 // It also means you can pass the argument myString to methods.
 @synthesize myString;

 -(id)initWithMyString:(NSString *)cantBeCalledMyStringNow
 {
     if ((self = [super init]))
     {
         // Woops I assigned straight to the iVar. So it’s not retained now
         myString = cantBeCalledMyStringNow;
     }
     return self;
 }

 +(id)myClassWithMyString:(NSString *)cantBeCalledMyStringNow
 {
     return [[self initWithMyString: cantBeCalledMyStringNow] autorelease];
 }

iOS Memory Management Basics

  • 1.
    iOS & Memory Management Basics Cameron Barrie - @whalec
  • 2.
    iOS & Memory Management Memory Management Programming Guide: https://developer.apple.com/iphone/library/ documentation/Cocoa/Conceptual/MemoryMgmt/ MemoryMgmt.html
  • 3.
    iOS Memory Management alloc/copy/retain/release/autorelease Program received signal: "EXC_BAD_ACCESS".
  • 4.
  • 5.
    iOS Memory Management ObjectiveC objects contain a ‘count’ of how many other objects are currently holding onto them. You increment that count with the retain message. You decrement that count with the release message. When that count hits 0. The object is deallocated from memory
  • 6.
  • 7.
    iOS Memory Management MemoryManagement Rules: 1. You only release objects you own:
  • 8.
    iOS Memory Management MemoryManagement Rules: 1. You only release objects you own: [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil]
  • 9.
    iOS Memory Management Memory Management Rules: 1. You only release objects you own: [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil] NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy];
  • 10.
    iOS Memory Management Memory Management Rules: 1. You only release objects you own: [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil] NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; 2. Or objects you take ownership of:
  • 11.
    iOS Memory Management Memory Management Rules: 1. You only release objects you own: [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil] NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; 2. Or objects you take ownership of: [[UIFont fontWithName:@"HoboStd" size:25] retain]
  • 12.
    iOS Memory Management Memory Management Rules: 1. You only release objects you own: [[UPGameViewController alloc] initWithNibName:@"UPGameView" bundle:nil] NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; 2. Or objects you take ownership of: [[UIFont fontWithName:@"HoboStd" size:25] retain] Retaining an object simply increments an objects retainCount by 1.
  • 13.
    iOS Memory Management Releasingan object Release an object by sending it the release message
  • 14.
    iOS Memory Management Releasing an object Release an object by sending it the release message NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; [mutableTopLevelObjects release];
  • 15.
    iOS Memory Management Releasing an object Release an object by sending it the release message NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"UPLeaderboardViewCell" owner:nil options:nil]; NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; [mutableTopLevelObjects release]; Releasing an object doesn’t remove it from memory. It simply decrements the objects retainCount by 1. When an objects retainCount is equal to 0. The object is deallocated by the runtime automatically.
  • 16.
    iOS Memory Management Releasing an object Release an object by sending it the release message NSMutableArray *mutableTopLevelObjects = [topLevelObjects mutableCopy]; [topLevelObjects retainCount]; // => 1 [topLevelObjects retain]; [topLevelObjects retainCount]; // => 2 [mutableTopLevelObjects release]; [topLevelObjects retainCount]; // => 1 [topLevelObjects release]; [topLevelObjects retainCount]; // => 0 Releasing an object doesn’t remove it from memory. It simply decrements the objects retainCount by 1. When an objects retainCount is equal to 0. The object is deallocated by the runtime automatically.
  • 17.
    iOS Memory Management Sowhat about the other objects?
  • 18.
    iOS Memory Management Sowhat about the other objects? They’re what’s known as autorelease objects.
  • 19.
    iOS Memory Management So what about the other objects? They’re what’s known as autorelease objects. // This object will be automatically released at some point // in the future when the autorelease pool is drained NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1];
  • 20.
    iOS Memory Management So what about the other objects? They’re what’s known as autorelease objects. // This object will be automatically released at some point // in the future when the autorelease pool is drained NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1]; You can mark your own objects as autorelease objects
  • 21.
    iOS Memory Management So what about the other objects? They’re what’s known as autorelease objects. // This object will be automatically released at some point // in the future when the autorelease pool is drained NSString *aString = [NSString stringWithFormat:@"a string with an int %i", 1]; You can mark your own objects as autorelease objects [topLevelObjects retainCount]; // => 1 [topLevelObjects autorelease]; [topLevelObjects retainCount]; // => 1 since it will be released later
  • 22.
    iOS Memory Management NSAutoreleasePool “Cocoa always expects there to be an autorelease pool available” - Memory Management Programming Guide: Autorelease Pools // main.m // The main entry point into the app sets up // an autorelease pool for us automatically int main(int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, nil, nil); [pool release]; return retVal; }
  • 23.
  • 24.
    iOS Memory Management Commonmistakes // You need to mark zero for autorelease or release it - (void)reset { NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; [self setCount:zero]; }
  • 25.
    iOS Memory Management Commonmistakes // You need to mark zero for autorelease or release it - (void)reset { NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; [self setCount:zero]; } // zero is an autorelease object already. // you haven't used alloc/copy anywhere // you are over releasing the zero object - (void)reset { NSNumber *zero = [NSNumber numberWithInteger:0]; [self setCount:zero]; [zero release]; }
  • 26.
    iOS Memory Management Commonconfusion // Adding an object to a collection retains the object // It transfers ownership to the parent collection // Since alloc/copy was never called you don’t need // to release convenienceNumber NSMutableArray *array = [[NSMutableArray alloc] init]; NSUInteger i = 0; for (i; i < 10; i++) { NSNumber *convenienceNumber = [NSNumber numberWithInteger:i]; [array addObject:convenienceNumber]; }
  • 27.
    iOS Memory Management Commonconfusion // Adding an object to a collection retains the object // It transfers ownership to the parent collection // You need to release allocedNumber here since you alloced it. NSMutableArray *array = [[NSMutableArray alloc] init]; NSUInteger i = 0; for (i; i < 10; i++) { NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger: i]; [array addObject:allocedNumber]; [allocedNumber release]; }
  • 28.
    iOS Memory Management ReturningObjects from Methods
  • 29.
    iOS Memory Management ReturningObjects from Methods // Correct - You don't own the string object so you should return it as such. - (NSString *)fullName { NSString *string = [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; return string; }
  • 30.
    iOS Memory Management ReturningObjects from Methods // Correct - You don't own the string object so you should return it as such. - (NSString *)fullName { NSString *string = [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; return string; } // Incorrect - You're returning an object that has already been released. - (NSString *)fullName { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] release]; return string; }
  • 31.
    iOS Memory Management ReturningObjects from Methods // Correct - You don't own the string object so you should return it as such. - (NSString *)fullName { NSString *string = [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; return string; } // Incorrect - You're returning an object that has already been released. - (NSString *)fullName { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] release]; return string; } // Correct - You've created an autorelease object. - (NSString *)fullName { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] autorelease]; return string; }
  • 32.
    iOS Memory Management AccessorMethod - @property/@synthesize
  • 33.
    iOS Memory Management AccessorMethod - @property/@synthesize // MyClass.h @property(nonatomic, readwrite, retain) NSString *myString
  • 34.
    iOS Memory Management AccessorMethod - @property/@synthesize // MyClass.h @property(nonatomic, readwrite, retain) NSString *myString // MyClass.m @synthesize myString = _myString; -(id)init { if ((self = [super init])) { self.myString = @"A string to be retained"; } return self; } -(void)dealloc { [_myString release], _myString = nil; [super dealloc]; }
  • 35.
    iOS Memory Management AccessorMethod - @property/@synthesize // MyClass.h // Will retain the variable sent to it. @property(nonatomic, readwrite, retain) NSString *myString; // Will not retain the variable sent to it. @property(nonatomic, readwrite, assign) NSString *myWeakString;
  • 36.
    iOS Memory Management AccessorMethod - @property/@synthesize // MyClass.m // Will retain the variable sent to it. @synthesize myString = _myString; // The @synthesize produces a setter/getter combo(readwrite) -(NSString *)myString { return _myString; } -(void)setMyString:(NSString *)myString { if (myString != _myString) { [_myString release]; _myString = [myString retain]; } }
  • 37.
    iOS Memory Management AccessorMethod - @property/@synthesize // MyClass.m // Will not retain the variable sent to it. @synthesize myWeakString = _myWeakString; // The @synthesize produces a setter/getter combo(readwrite) -(NSString *)myWeakString { return _myWeakString; } -(void)setMyWeakString:(NSString *)myWeakString { _myWeakString = myWeakString; }
  • 38.
    iOS Memory Management AccessorMethods - @property/@synthesize // MyClass.m // By synthesizing in this way you are protecting your iVar so it can // only be accessed through the setter. // It also means you can pass the argument myString to methods. @synthesize myString = _myString; -(id)initWithMyString:(NSString *)myString { if ((self = [super init])) { self.myString = myString; } return self; } +(id)myClassWithMyString:(NSString *)myString { return [[self initWithMyString:myString] autorelease]; }
  • 39.
    iOS Memory Management AccessorMethods - @property/@synthesize // MyClass.m // By synthesizing in this way you are protecting your iVar so it can // only be accessed through the setter. // It also means you can pass the argument myString to methods. @synthesize myString; -(id)initWithMyString:(NSString *)cantBeCalledMyStringNow { if ((self = [super init])) { // Woops I assigned straight to the iVar. So it’s not retained now myString = cantBeCalledMyStringNow; } return self; } +(id)myClassWithMyString:(NSString *)cantBeCalledMyStringNow { return [[self initWithMyString: cantBeCalledMyStringNow] autorelease]; }