iOS Interview Prep 1 — Memory management
The purpose of this interview preparation series is to assist you in quickly refining your interview skills and thoroughly preparing for the typical questions asked during an iOS interview. If you find it useful, please leave a comment or tap the like button.
Overview
Memory management is one of the most frequently asked questions during iOS interview, it’s a huge red flag if you fail to demonstrate a good understanding of the basic concepts such as reference cycle, strong/weak reference. To prepare for all kinds of questions related to memory management, it’s key to understand the foundamental mechanism behind the curtain of ARC.
Interview Questions
- Explain how ARC works in Obj-C/Swift
- What are common situations that can lead to memory leak?
- What are some common scenarios where reference cycle might happen?
- When should you use copy property? How does it help you avoid bugs?
- Can you explain the difference between unowned(unsafe) and weak reference?
Auto Reference Counting
Memory management in iOS application is based on a reference counting model. When you initialize a new object, memory is allocated on the heap and reference count is set to 1. The reference count increases as more objects set strong reference to it.
On the contrary, if the owner object relinquishes the strong reference, the reference count will decrease by 1. Once the reference count becomes zero, the memory will be destroyed as a result.
When compiling code with ARC feature, the compiler takes the references you create and automatically inserts calls to the underlying memory management mechanism.
Strong, Weak and Unowned
With the introduction of Automatic Reference Counting(ARC), we only need to specify the type of ownership when referencing an object
- Strong references — ensures that the referenced object remains in memory for as long as the reference is valid.
- Weak references — which have no effect on the lifetime of a referenced object.
- Unowned references — an unowned doesn’t keep a strong hold like weak reference
It’s important to understand the difference between weak and unowned
- When referenced object gets deallocated, weak reference will be set to nil while unowned reference will become a dangling pointer, sending a message to it will result a crash
- Unowned is used when the other instance has the same or longer lifetime
- Unowned reference is expected to always have a value, so ARC never sets it to nil
when to use strong/weak/assign
- use strong to retain objects — although the keyword retain is synonymous, it’s best to use strong instead
- use weak if you only want a pointer to the object without retaining it — useful for avoid retain cycles (ie. delegates) — it will automatically nil out the pointer when the object is released
- use assign for primatives — exactly like weak except it doesn’t nil out the object when released (set by default)
Avoid Strong Reference Cycle
If you have a good understanding of reference couting behind ARC, then it will be really easy to grasp the idea of reference cycle. If two objects are connected by a circle of strong reference, then they will keep each other alive even if there are no other strong reference.
Reference Cycles in Closures/Block
One of the common situation where strong reference cycle can be introduced is when using closure/block. A strong reference cycle can occur if you assign a closure/block to a property of a class instance, and the body of that closure/block captures the instance(self). Note that if you simply create a new block without assigning it to a property, it won’t cause any reference cycle.
- (void)configureBlock {
// capture the weak reference to avoid the reference cycle
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf != nil) return;
[strongSelf doSomething];
}
}
Swift provides an elegant solution to this problem, known as a closure capture list
lazy var someClosure = { [weak self] in
// closure body goes here
guard let strongSelf = self else { return }
}
Retain self or not
Strongly capturing self
in a GCD async
closure will not cause a reference cycle, but it will extend the lifetime of self.
For instance, if you make a network request from a view controller that has been dismissed in the meantime, the closure will still get called. If you capture the view controller weakly, it will be nil
.However, if you capture it strongly, the view controller will remain alive until the closure finishes its work
Copy Properties in Objective-C
In practice we use copy property for class that has a mutable version such as NSString, NSArray. So that our property maintains its own copy, therefore will not be impacted if the original mutable variable is updated.
@interface XYZBadgeView : NSView
@property NSString *firstName;
@property NSString *lastName;
@end
// If you need to set a copy property's instance variable directly
- (id)initWithSomeOriginalString:(NSString *)aString {
self = [super init];
if (self) {
_instanceVariableForCopyProperty = [aString copy];
}
return self;
}
- (void)example {
NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
// If we don't create a copy then firstName will also be affected
// Because it points to the same object as nameString
[nameString appendString:@"ny"];
}
iOS Interview Prep Series
iOS Interview Prep 1 — Memory management iOS Interview Prep 2 — Autorelease Pool iOS Interview Prep 3 — Blocks and Closures iOS Interview Prep 4 — Event Handling & Responder Chain iOS Interview Prep 5 — Singletons iOS Interview Prep 6 — Dependency Injection iOS Interview Prep 7 — Concurrency Part 1 iOS Interview Prep 7 — Concurrency Part 2 iOS Interview Prep 8 — View and Layout