Memory Management Part II

In part one of this series we talked about the heap, the stack, object ownership, and how reference counting works. In this article we’re going to expand on this to include the role of properties and how all of this works in ARC (Automatic Reference Counting).

Assumptions

Properties

In Memory Management Part 1, I mentioned that an Objective-C property is basically just an ivar (instance variable) with auto generated getters and setters. Well that’s halfway true. Properties also can have attributes that will determine how they behave in memory for both single and multithreaded applications. You can also use attributes to set custom getter and setter names. Before moving on to attributes, lets see how a property would look if it wasn’t done for us automatically.

SomeNinjaClass.h


1
2
3
4
5
6
7
#import <Foundation/Foundation.h>

@interface Ninja : NSObject

@property NSString *ninjaName;

@end

And the compiler would generate a setter and getter in the implentation file.

SomeNinjaClass.m


1
2
3
4
5
6
7
8
9
#import "Ninja.h"

- (NSString *)ninjaName {

    return _ninjaName;
}
- (void)setNinjaName:(NSString *)ninjaName {
    _ninjaName = ninjaName;
}

Now you can access these using either the bracket notation or the dot notation:


1
2
3
4
5
6
7
//Dot Notation
self.ninjaName = @"Haru";
NSLog(@"The Ninja's name is %@",self.ninjaName);

//Bracket Notation
[self setNinjaName:@"Haru"];
NSLog(@"The Ninja's name is %@",[self ninjaName]);

Take note here that althought the method is actually “setNinjaName” you don’t need to include “set” when using dot notation.

Now that we undestand what happens when you create a property, lets talk about property attributes.

Property Attributes

There are basically three types of attributes:

  • Types that let you choose custom getters and setters
  • Types that control how a property behaves in multithreaded applications
  • Types the control how a property behaves in memory

Custom Getter, Setter, and Readonly

Sometimes, for readability it makes sense to change the names of your getters and setters. Say for instance we want a property that lets us know our ninja is jumping. We would create a property as we always do called ninjaJumping:


1
@property BOOL ninjaJumping;

Which would create the two accessors


1
2
3
4
5
6
7
- (BOOL)ninjaJumping {
    return _ninjaJumping;
}

- (void)setNinjaJumping:(BOOL)ninjaJumping {
    _ninjaJumping = ninjaJumping;
}

But wouldn’t it make more sense if we ask “is ninja jumping?” rather than “ninja jumping?” Well we can do that using attributes when we declare a property!


@property (getter = isNinjaJumping) BOOL ninjaJumping;

Now you can access the properties using your custom getter and setter:


1
2
NSLog(@"Ninja Jumping? %hhd", self.isNinjaJumping);
[self setNinjaJump:YES];

The readonly attribute is really simple. All it does is causes the compiler to omit the setter method, so there is only a getter. If you can’t set a value it’s read only right?

Nonatomic or Atomic? that is the question!

When you are considering whether or not to use the “nonatomic” or “atomic” attributes you should really be answering one question: “Will this property be accessed concurrently?” At the heart of it, that’s what these two attributes are for. By default, “atomic” is automatically set as it is the safest of the two options. By using the atomic attribute you effectively lock around the ivar backing the property, so that competing threads are serialized. You can see how this could be useful in a multithreaded application where the getter and setter can potentially be accessed at the same time.

So why not always use automic? In a word, there’s too much overhead. For most properties you will actually want to use “nonatomic” as they won’t need thread safety.

Strong, Weak, and Copy

These attributes are basically there to determine how much ownership you want over a property in Automatic Reference Counted applications. You can use these attributes to determine how long you need a property to stay in memory.

A strong attribute basically is the same as creating an object and sending a “retain” message. In other words, when you create the property object it gets created with a retain count of 1, insuring that as long as you’re using it, it won’t get destroyed. Most of the time you’ll want ot use a strong type for your properties.

A Weak attribute will create a property with no retain count, so unless another object takes ownership of it and thus increases it’s retain count, it will be deallocated. The weak attribute will be necessary to prevent retain cycles, which causes memory to never get deallocated. This can happen a lot when dealing with blocks. We’ll talk about retain cycles more in a moment. Additionally, weak properties are auto-zeroing. When the object being referenced is deallocated a weak property will automatically be set to nil, helping avoid dangling pointers.

A Copy attribute is good for situations where you want to copy anything you assign to the property rather than take ownership of it. This is like making a copy of some other object and calling retain on it. This can be good for working with mutable data like a string and you don’t want to change it’s value. A quick example should illustrate it’s usefulness:


1
2
3
4
5
6
7
8
9
10
11
//Define the property in the interface like this
//Ninja.h
@property (nonatomic,copy) NSString *ninjaName

//And in a method somewhere we may have a situation like this
Ninja *ninja = [[Ninja alloc] init];
NSMutableString *fullName = @"Haru Farley";
ninja.fullName = fullName;

fullName = @"Haru has no last name"; //here we change fullName
NSLog(@"%@", ninja.fullName); //but this one doesn't change, because it's a copy

We won’t get into it here, but the copy attribute is also useful when you want to move a block, which is a stack variable onto the heap. Just so you know.

The Retain Cycle

Sometimes you end up in a situation where you have a parent child relationship between two objects. For instance a Father has a son and a son has a father. This two way relationship can cause problems when dealing with strong properties.

So imagine we have two classes for this relationship, a sensei and his ninja pupil.

They each have properties for each other, and they each have a name. Their class interfaces look like the following:

Ninja.h


1
2
3
4
5
6
7
@class Sensei;
@interface Ninja : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) Sensei *sensei;

@end

Sensei.h


1
2
3
4
5
6
7
@class Ninja;
@interface Sensei : NSObject

@property(strong, nonatomic) NSString *name;
@property(strong, nonatomic) Ninja *pupil;

@end

Note: The @Class Sensei and @Class Ninja is there to keep an endless loop happening. If we were to import each class into the other, they would never stop importing. Rather than importing we use the @class decleration to let the compiler know that the class actually DOES exist without importing it.

Now Imagine we had this kind of code in a method somewhere:


1
2
3
4
5
6
7
8
    Sensei *sensei = [[Sensei alloc] init];
    sensei.name = @"Sensei";

    Ninja *pupil = [[Ninja alloc] init];
    pupil.name = @"Haru";

    sensei.pupil = pupil;
    pupil.sensei = sensei;

Following what we know from the first Memory Management article, When we set “pupil” to sensei.pupil and set “sensei” to pupil.sensei. We cause them each to hold a reference to each other. This means that the reference count can never go to 0. What we have here is a retain cycle, These two objects will stay in memory forever, or until the app crashes.

To fix this situation, we need to assign weak to one of our properties. Which property you ask? Well it’s not always straight forward, but generally you want to establish a parent-child relationship and give the child the weak attribute. In this case, the Ninja pupil needs the weak attribute.

Sensei.h


1
2
3
4
5
6
7
@class Ninja;
@interface Sensei : NSObject

@property(strong, nonatomic) NSString *name;
@property(weak, nonatomic) Ninja *pupil;

@end

Throwback Attributes

Now there are a few attributes you may use from time to time that aren’t strong, weak, and copy.

A Retain attribute is basically the same thing as strong, but for manual reference counting. Using “retain” will take ownership of an object by incrementing its reference count.

An unsafe_unretained Attribute is basically the manual version of weak, except it won’t set it’s value to nil if the object is destroyed. Again, only needed if not using ARC.

The Assign attribute is used solely for giving a property-like behavior to a primitive data type such as a int so you can access it anywhwere in the application.

Automatic Reference Counting

And finally we have made it to automatic reference counting (ARC). The good news is that it’s really quite simple if you already understand manual reference counting. The basic gist of ARC is it handles most of the memory management for you by doing the reference counting automatically. All you need to do is assign strong, weak, and copy appropriately to your properties.

Remember Code Chunk 2 from memory management part I? Here it is again, so you don’t have to go back to it. This example shows the reference couning and how to property handle instance variables with Manual Reference Counting.


1
2
3
4
5
6
7
8
9
10
NSMutableArray *array = [[NSMutableArray alloc] init];

NSString *string = [[NSString alloc] initWithFormat:@"A String"];    // +1
[array addObject:string];                                            // +1
[string release];                                                    // -1
[array release];                                                     // -1
                                                                     //=====
                                                                     //  0

NSLog(@"%@",string); //This line will throw a EXC_BAD_ACCESS  error since "string" is now deallocated

Let’s refactor it for ARC.


1
2
3
NSMutableArray *array = [[NSMutableArray alloc] init];
NSString *string = [[NSString alloc] initWithFormat:@"A String"];    
[array addObject:string];

Tada! No more releasing or autoreleasing. Just make your variables and let ARC worry about releasing them.

Wrapping Up

Well I hope I’ve shed some light on memory management, at least as it pertains to properties and instance variables. There’s a bit more when it pertains to blocks, and I hope to complete a “Memory Management Part III” article to explain how blocks work in memory.

About Joe Hoffman

I am An Electrical Engineer that spends a lot of my off time doing web development and other programming. Currently I am trying to expand my knowledge with iOS and I find that writing tutorials helps me learn more thoroughly as well as provide some useful info to others.

Speak Your Mind

*

css.php
Privacy Policy