1. Explain what ARC is and how it works
Since it doesn’t make much sense to talk about the old retain-release cycle, instead I like to find out if the candidate actually knows what ARC really is, or if they just consider a bit of Apple magic. ARC stands for Automatic Reference Counting, it is not a runtime process but rather a preprocessor system which inserts retain, release and autorelease calls into your code before it is compiled. A twist to this question would be to ask what are some of the things you need to be careful about when using ARC? The answers are the same as with normal memory management, avoid over retains and retain cycles.
2. What is NSZombies?
A lot of newer developers haven’t encountered NSZombies yet, they may have heard about it but likely won’t understand exactly how it works. NSZombies is a runtime process that you can turn on with an environment variable, when it is on released objects are not returned to the heap, instead they are replaced with a “zombie” version of their class, for example _NSZombie_NSString. These zombie classes implement receiveMessage to crash the application. The twist to this question is to ask why crashing the application is useful? The answer is that when it crashes, the object which called it will be in the stack trace — therefore you can quickly see where you are accessing a released object, without NSZombies the crash would happen in the next class which uses the same address, this could be quite distant from the spot where the bug really is.
3. Why does your app crash when the device is low on memory?
Every developer knows that iOS will terminate your application if the device is low on memory. Not all of them know or even think about why that is. The answer can be quite deep, depending on the candidate. First, you need to understand that iOS devices use virtual memory with paging, but unlike desktop systems there is no backing store (no hard drive essentially) so there is a limit to the number of pages available. This environment then leads to conditions where some apps, such as safari or itunes, can be using many pages even when they are not active, the pages they are using take away from the pages your app is allowed to use. This means that even if your app only allocates a couple megabytes on launch, it may still crash if no other apps release their pages — your allocations will fail. The OS tries to give priority to the active application by terminating background apps, but if you are allocating a large buffer (such as a photo) or quickly allocating small buffers, the OS might not be able to free up pages quickly enough.
4. How is NSDictionary implemented?
This is an interesting question to me because it really tests how the candidate thinks about the tools they are using. Some developers think about the Apple APIs as magic boxes that “just work”, others have an innate curiosity into how Apple made all this stuff work. This question does have a correct answer: CFDictionary is open source. That’s not important though, its more important to get the candidate talking about implementation details. Specifically you’ll be talking about hash tables, so run through the normal questions for those: “What are the performance characteristics for insert and lookup?”, “What does it mean for a hash table to be sparse or dense?”, “What happens to performance if your key function maps to a single value?” and similar questions.
5. What is a retain-cycle and how do you find and fix them?
Even in the post-ARC world, retain-cycles still cause a lot of trouble. They sneak up on you and can eat up devastating amounts of memory. A retain-cycle is when two objects hold strong references to each other, no matter what order the objects are released in they’ll never both get released. Typically the leaks tool is not able to detect these kinds of errors because the references are to valid living objects. An example would be if you display a help view controller with a 1 megabyte image on it and then dismiss it. You would expect that 1 megabyte to be released, but if there is a retain cycle then it won’t be and neither ARC nor leaks will tell you about it.
Finding retain cycles is relatively easy, once you know the trick. You use the allocations tool and “mark” the heap before your event (presenting a view) and again after the event (dismissing the view), any size difference between the two snapshots is possible due to retain cycles. You can look at the objects which didn’t get released in instruments and look for anything that you think should have, then you go back to the code and troubleshoot why it didn’t.
6. Explain the difference between a category and a protocol
This question is another quick way to figure out the level of experience the candidate really has. Most people will have heard about categories and protocols, more experienced developers will have used both — and the best developers will laugh a bit at the question because the two are completely unrelated concepts.
A category is a way to extend a class by adding functions to it, for example I could create a category function for UILabel called “decorate” which sets the font of the label. After doing that I can call “decorate” on any UILabel in my project, just like Apple had coded it that way. A protocol is roughly equivalent to an interface in other languages, it defines a set of functions which a class implements, and provides a way for other classes to be guaranteed that the object they are dealing with will respond to certain messages.
7. What does it mean to call objective-c a messaging language?
I usually close an interview with this question, I like it because it requires the candidate to know at least one other language to contrast objective-c with in order to answer it properly. In a procedural language like C, when you call a function, that functions pointer is placed on the stack and the execution pointer jumps to it immediately. In objective-c, when you call a function you place your request to call a function onto the runtime queue. Later the runtime will pop your request and do the actual call. The asynchronous nature of this operation is the key difference. Once the candidate gets this far you can ask why this is good and how it could be bad. One way it can be good is because we can alter the destination of a message at runtime by switching the implementations, a drawback to messaging is that adds a bit of overhead to every call — doing it a lot in a tight loop can degrade the performance of your app.
So those are most of my typical interview questions, hopefully this will be helpful to some of you. Don’t bother rehearse those if you are going to interview with me, I saved a few others you don’t know about and each of these is open-ended enough to draw out a conversation even if you have a prepared answer.