Before talking about strongSelf and weakSelf, I need briefly explain retain cycle.

So, a retain cycle usually occurs when an object A has a strong reference to Object B, and Object B also has a strong reference to Object A. Under this situation, the retainCount for both objects can not be 0, so the memory for these two objects won’t be released. This is the memory leak. The retain cycle could happen between multiple objects as long as their references between each other form a cycle.

Retain cycle 1Retain cycle 1

Also, an object can have a reference of itself which will cause retain cycle too. The most common situation is that an object owns a block, and in the block, we call any of this object’s methods or properties. Then the block has a reference to this object itself, which cause a retain cycle. Notice that blocks maintain strong references to any captured objects, including self, because they don’t want data be destroyed by ARC before themselves getting executed.
Retain cycle 2Retain cycle 2

Example 1:

I have an object called Car. Car has a block called drive.

1
2
3
4
5
6
7
8
// car.h
#import <Foundation/Foundation.h>
typedef void(^Drive)();

@interface Car : NSObject
@property (nonatomic, copy) NSString *miles;
@property (nonatomic, copy) Drive drive;
@end

In the viewController.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#import "ViewController.h"
#import "Car.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

Car *car = [[Car alloc]init];
car.miles = @"100 miles";

car.drive = ^{
NSLog(@"Car drived %@", car.miles);
};

car.drive();
NSLog(@"return");
}
@end

Leak! Here, the car has a strong reference to the drive block, and in the block, the block has a strong reference to the car since we called car.miles. This made the car has a reference to itself.

Using Instruments to detect the leak. Click the red cross. Malloc 48 Bytes means the system allocate 48 Bytes of memory to the block.

Open Cycles & Roots. You can see the cycle.

no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message.no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message.

Change the Example 1 to Example 2.

Example 2:

I pass a parameter into the block. Leak?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#import "ViewController.h"
#import "Car.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

Car *car = [[Car alloc]init];
car.miles = @"100 miles";

car.drive = ^(NSString *miles){
NSLog(@"Car drived %@", miles);
};

car.drive(car.miles);
NSLog(@"return");
}
@end

No Leak. Checking the leak with instruments:

Since I pass the car.miles into the block as a parameter, and the block won’t retain the parameter, there will be no retain cycle.

WEAKSELF AND STRONGSELF

weakSelf

How to create a weakSelf? There are two ways.

1
2
__weak __typeof(self) weakSelf = self; 
// Write this code every time before you use weakself.
1
2
#define WEAKSELF typeof(self) __ weak weakSelf = self  
// Or create a macro in header file, then you can use WEAKSELF everywhere.

The reason we use weakSelf in a block is that with weak property, the block won’t retain the object in the block. Then we break the cycle. For example 1, we can use weakself to solve the retain cycle problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import "ViewController.h"
#import "Car.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

Car *car = [[Car alloc]init];
car.miles = @"100 miles";

__weak __typeof(car) weakCar = car;
car.drive = ^{
NSLog(@"Car drived %@", weakCar.miles);
};

car.drive();
NSLog(@"return");
}
@end

strongSelf

1
__strong __typeof(weakSelf) strongSelf = weakSelf;
1
#define STRONGSELF typeof(weakSelf) __strong strongSelf = weakSelf

Since we use weakSelf in the block to prevent the retain cycle problem, there is a potential problem that the object could be released before the block has been executed.

example 3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "ViewController.h"
#import "Car.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

Car *car = [[Car alloc]init];
car.miles = @"100 miles";

__weak __typeof(car) weakCar = car;
car.drive = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Car drived %@", weakCar.miles);
});
};
car.drive();
NSLog(@"return");
}
@end

I add a delay before executing the NSlog(). Then the output is:
... 15:28:20.875923 BlockTest[7630:4429580] return ... 15:28:23.065725 BlockTest[7630:4429580] Car drived (null)

What is happening here? The dispatch_after() function submits the block (which contains NSLog()) to the given queue (Here is the main queue) at the time specified by the when (Here is after 2 sec) parameter. Think the block as a task. The dispatch_after() asynchronously add the task to the main queue after two sec when you execute the study block. Since the study block has a weak reference to the car, after the study block has been execute (car.drive() is called), the weakCar is released by ARC, then the weak object will be set as nil. However, the dispatch block is still not executed. That is why we got null in the output.

So, we add strongSelf in the block which prevent the object will not be released inside the block. After the block is executed, strongSelf then release.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#import "ViewController.h"
#import "Car.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

Car *car = [[Car alloc]init];
car.miles = @"100 miles";

__weak __typeof(car) weakCar = car;
car.drive = ^{
__strong __typeof(weakCar) strongCar = weakCar;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Car drived %@", strongCar.miles);
});
};

car.drive();
NSLog(@"return");
}
@end