inaka

Latest blog entries

/
The Art of Writing a Blogpost

The Art of Writing a Blogpost

Mar 09 2017 : Matias Vera

/
SpellingCI: No more spelling mistakes in your markdown flies!

Feb 14 2017 : Felipe Ripoll

/
Fast reverse geocoding with offline-geocoder

Do you need a blazing fast reverse geocoder? Enter offline-geocoder!

Jan 18 2017 : Roberto Romero

/
Using Jayme to connect to the new MongooseIM REST services

MongooseIM has RESTful services!! Here I show how you can use them in an iOS application.

Dec 13 2016 : Sergio Abraham

/
20 Questions, or Maybe a Few More

20 Questions, or Maybe a Few More

Nov 16 2016 : Stephanie Goldner

/
The Power of Meeting People

Because conferences and meetups are not just about the technical stuff.

Nov 01 2016 : Pablo Villar

/
Finding the right partner for your app build

Sharing some light on how it is to partner with us.

Oct 27 2016 : Inaka

/
Just Play my Sound

How to easily play a sound in Android

Oct 25 2016 : Giaquinta Emiliano

/
Opening our Guidelines to the World

We're publishing our work guidelines for the world to see.

Oct 13 2016 : Brujo Benavides

/
Using NIFs: the easy way

Using niffy to simplify working with NIFs on Erlang

Oct 05 2016 : Hernan Rivas Acosta

/
Function Naming In Swift 3

How to write clear function signatures, yet expressive, while following Swift 3 API design guidelines.

Sep 16 2016 : Pablo Villar

/
Jenkins automated tests for Rails

How to automatically trigger rails tests with a Jenkins job

Sep 14 2016 : Demian Sciessere

/
Erlang REST Server Stack

A description of our usual stack for building REST servers in Erlang

Sep 06 2016 : Brujo Benavides

/
Replacing JSON when talking to Erlang

Using Erlang's External Term Format

Aug 17 2016 : Hernan Rivas Acosta

/
Gadget + Lewis = Android Lint CI

Integrating our Android linter with Github's pull requests

Aug 04 2016 : Fernando Ramirez and Euen Lopez

/
Passwordless login with phoenix

Introducing how to implement passwordless login with phoenix framework

Jul 27 2016 : Thiago Borges

/
Beam Olympics

Our newest game to test your Beam Skills

Jul 14 2016 : Brujo Benavides

/
Otec

Three Open Source Projects, one App

Jun 28 2016 : Andrés Gerace

/
CredoCI

Running credo checks for elixir code on your github pull requests

Jun 16 2016 : Alejandro Mataloni

/
Thoughts on rebar3

Thoughts on rebar3

Jun 08 2016 : Hernán Rivas Acosta

/
See all Inaka's blog posts >>

/
Memory Management Changes in iOS 5

German Azcona wrote this on September 05, 2011 under 'ios, 5', apple, arc, dev, ios, memory, release, retain .

[Editor's note: We forgot to post this article when German wrote it back in September, but here it is now.]

It's been some time since Apple's WWDC this year, so it's time we get into the new technology and changes the guys at Cupertino made for us, the developers. This time, we'll talk about Memory Management and what Apple did to make things better, and, maybe, worse.

Overview

To understand these changes, we need to review the current state on memory management. On Objective-C we use the concept of ownership. An object can have one or several owners and gets destroyed when it doesn't have any owners. This is implemented internally by using an internal counter. When someone claims ownership, they send a retain message to the object so the counters go up by one and when they relinquish ownership a release or autorelease message is sent to the object and the counter goes down by one. When it reaches 0, the object gets destroyed or deallocated.

The autorelease message marks an object for a later release. The ownership is relinquished at the end of the scope defined by the current autorelease pools. This allows a method to return a valid object so it can be used without anyone else needing to take ownership during that scope. All this management is pretty extensive and is not what I am trying to address with this post so I will just leave it there.

So, to clarify ownership, Cocoa sets this policy: + You own an object you create using methods that start with alloc, new, copy, mutableCopy. + You take ownership sending the retain message. + You must relinquish ownership when you are done by sending the release or autorelease message. + You must not relinquish ownership when you are not the owner.

This is, in a nutshell, the current state of memory management in Objective-C for iOS. For Mac OS X developers, there are other options like garbage collection, but I understand that even that may be troublesome and is not, generally speaking, the recommended way to go.

The Problem

The manual memory rules are seemingly easy to follow. Remembering to release, to nil weak references, and such practices can become second nature to an experienced Objective-C developer, but can be really challenging to new developers. And even for more experienced people, it can sometime cause a headache or two.

This is because memory management on Objective-C relies on the following of conventions and your following of those conventions perfectly. Now we all know that people make mistakes. So it is not unusual that someone might forget a release. If that happens the counter doesn't reach 0, the object remains alive without being used and thus, the infamous leak is created. If enough leaks happen, the device runs out of memory, and the OS kills your app. This is perceived as a crash. The opposite is also true, when someone overreleases an object, it will make it deallocate with references still pointing at it, so when trying to use that object later (even if only to release it), another crash occurs.

Crashes can become a big problem. In fact, Apple stated that crashes are the number one reason for app rejection from the app store.

A solution to this issue is what other platforms are doing: Garbage Collection. All the cool kids are doing it, even apps for Mac OS X has Garbage Collection, so why not iOS, right? Apple seems to disagree, claiming that mobile devices are better off without Garbage Collection due to performance costs.

Reality dictates that Apple doesn't like Garbage Collection. Period. New Mac OS X application projects don't even enable it by default. Some claim that Objective-C's garbage collection doesn't work well in every situation, and that it can't work in every situation given to certain ambiguities that can come up due to its dependency on C.

Whatever the reason is, Apple will continue to use Objective-C and wants memory management to be better.

The Solution: ARC

So Apple rolled out a new language feature called Automatic Reference Counting or ARC. ARC is about simplifying retain/release programming, and to make Objective-C a higher lever language by doing a lot of automatic memory management for Objective-C objects. The basic idea of ARC is that you don't have to write a retain,release, or autorelease line of code ever again because the compiler will synthesize them all automatically.

This is achieved, technically, by applying local rules, and optimizing redundancies. The rules apply to any Objective-C object and block (which is an object in essence) pointer on any scope. To determine these rules, four kinds of ownership where determined: strong references, autoreleasing references, unsafe references and weak references.

Strong

Strong references are managed like a retained property, they are initialized to nil and their current value is implicitly released. This is the default for all variables. To be clear, let's lay out a couple of examples, and what happens with ARC.

On Non-ARC you did:

NSString * name = [[NSString alloc] init];
    ... do something with name ...
[name release];
name = [otherName retain];
    ... do something else ...
[name release];

On ARC you just do:

NSString * name = [[NSString alloc] init];
    ... do something with name...
name = otherName;
    ... do something else ...

This is what ARC does for you (added in orange):

__strong NSString * name = [[NSString alloc] init];
    ... do something with name ...
[otherName retain];
NSString * oldName = name;
name =  otherName;
[oldName release];
... do something else ...
[name release];

Pretty much exactly the same you would have done anyway.

Autoreleasing

They describe out-parameters. This means that the returned references was sent a retain and then an autorelease. This is really useful for using objects without owning them on the scope of the object which called the method.

On Non-ARC, to return an autoreleasing error, you did:

- (void) processSomethingError:(NSError**)error {
    ...
    if (!valid) {
        *error = [[[NSError alloc] init] autorelease];
        ...
    }
}

On ARC you just do:

- (void) processSomethingError:(NSError**)error {
    ...
    if (!valid) {
        *error = [[NSError alloc] init];
        ...
    }
}

Again, pretty straightforward, this is what ARC does for you (added in orange):

- (void) processSomethingError:(__autoreleasing NSError**)error {
    ...
    if (!valid) {
        *error = [[[NSError alloc] init] autorelease];
        ...
    }
}

Unsafe Unretained

These are exactly like the traditional variables or the assign properties. They don't retain the referenced object. They are not initialized, and they don't have any extra logic and thus no restriction. These can become dangling references that cause crashes. They are used so they don't cause a retain circle.

NSString * aRetainedName = [[NSString alloc]init];
NSString * name = aRetainedName;
[aRetainedName release];
//name has become a dangling pointer from now on.
//It will crash the next time it is accessed.
[name doSomething];
//This crash since name is pointing to garbage

Weak

Weak references don't retain the object and are also used so they don't cause retain circles, but the runtime manages reads and writes and they become nil when the object gets deallocated fixing a lot of problems.

If you write this on ARC:

NSString * aStrongName = [[NSString alloc]init]; //this is a strong variable
__weak NSString * name = aStrongName;
aStrongName = nil; //aRetainedName is released and deallocated
[name doSomething];
//This won't crash since name became nil once the object was deallocated

This is what ARC does:

__strong NSString * aRetainedName = [[NSString alloc]init];
__weak NSString * name = aRetainedName;
[aRetainedName release]; //aRetainedName is released and deallocated
aRetainedName = nil;

name = nil;
// This happens on runtime, the system knows aRetainedName was deallocated
and also knows that name was pointing to it, so it zeroes the pointer.

[name doSomething];
// Name became nil once the object was deallocated
// and since messages sent to nil it's a no-op, it won't cause a crash.

Besides these changes Apple also made some optimizations on certain operations. NSObject release/retain are 2.5 faster, autoreleased pools, which got a new syntax and are now part of the language, are six times faster, and objc_msgSend is also 33% faster. Autorelease pools also put lower memory pressure, and object returns from pools are optimized up to work up to twenty times faster.

Limitations

All this comes with a couple of limitations. As we said, ARC is for Objective-C objects only, it will not free C's malloc() calls, it will not do any CFRetain/CFRelease for CoreFoundation's objects either.

If you enable ARC, you cannot access the old memory methods anymore (i.e. retain, release, autorelease). You cannot implement or overwrite these methods. The compiler will do all these automatically while gaining performance optimizations. I don't think a lot will be missed here.

You cannot put a pointer to an object inside a C struct. The compiler can't keep track of references and such so it can't really be done. Again, not a game changer since those kind of mixtures are not common and can be easily solved by migrating those structs to classes.

You cannot casually cast object pointers to or from C pointers. This is because the compiler needs to know if the pointer is retained. Before ARC you could cast a NSString to and from its Core Foundation counterpart, CFString. These are called toll-free casts and are really convenient in certain situations. So now, to be able to do this, there are new Core Foundations conversion APIs to handle ownership and some keywords to avoid ambiguity in those casts.

You cannot use NSAutoreleasePool anymore. Before ARC, NSAutoreleasePool could be used as an object. The problem with that is that it is not really an object but a front end for some background service. So, for example, if you tried to retain the pool, it would raise an exception. NSAutorelease does allow you to do some weird things, like allocating a pool and initialize it later, decide whether to send it a drain message or not, and so on. It's now been simplified by the new @autoreleasepool { } syntax added to the language. When the block finishes, the pool is drained.

Benefits

Apple claims that ARC makes your code safer, more stable, cleaner, easier to maintain, faster and easier to learn. Safer and more stable because the compiler will not make the mistakes related to retain and release a dev might. Setting dangling pointers to nil through the weak implementation also makes the code safer and takes care of a lot of issues.

It is also cleaner and easier to maintain because it has a lot less lines of code since you won't need to write the retain/release bits, dealloc methods, and certain circumstantial temporal variables just to retain a value.

Optimizations in common memory related functions are also nice changes on performance. Yet, I can't shake the feeling they may have been added in to compensate for the overhead that caused the the weak pointer implementation.

When first introduced to ARC, I wasn't sure it would make Objective-C easier to learn for new devs, mostly for the increases in the learning curve of the inherent memory management that's going on under the hood. This is because ARC doesn't change the way memory management works, it just makes it invisible most of the time. But the times you need to deal memory, you will have to understand the whole thing. So my concerns are based on the rather steep curve a learning dev will hit when finding a memory related issue within a piece of code and not being previously familiar with the inner mechanics of it. And even though I believe it still might be true, in practice, when teaching the basics on iOS projects to family members, I noticed it was incredibly relieving not needing to stop to clarify certain retain and release mechanics in the middle of an key concept I was trying to explain. It's also a lot less confusing in several situations, so, all in all, I agree ARC makes it easier for new people to come into the platform.

It's important to note that ARC is fully interoperable with non-ARC code. This is really great since you can keep using the external libraries and frameworks you have been using and also older code that can't be easily converted to ARC.

Should You Migrate to ARC?

ARC seems to be an improvement in almost every way and Apple stated that this is the way it wants to go and it's the future of Objective-C. They also enforce this by turning ARC on by default on every new Xcode project. Yet, for existing non-ARC projects, there are certain special scenarios where moving to ARC won't be possible due to the limitations needed by it to work, so those pieces of code may need be reworked to fit ARC.

All in all, ARC is a nice addition that will make Objective-C a higher level language, making it a better place in which to code.