DEV Community

Bored Avo πŸ₯‘
Bored Avo πŸ₯‘

Posted on

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. For more details check out the iOS Interview Prep Complete Guide

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 }
}
Enter fullscreen mode Exit fullscreen mode

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"];
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)