Skip to content

Commit db84caa

Browse files
dulmarodfacebook-github-bot
authored andcommitted
[website] Improve the documentation of CAPTURED_STRONG_SELF
Summary: make doc-publish Improved this by looking at a few examples of how developers fix these issues. Reviewed By: jvillard Differential Revision: D32647659 fbshipit-source-id: 288eed78e1
1 parent a2d02c5 commit db84caa

File tree

2 files changed

+156
-8
lines changed

2 files changed

+156
-8
lines changed
Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,82 @@
1+
This check is about when a strong pointer to `self` is captured in a block.
2+
This could lead to retain cycles or unexpected behavior since to avoid retain
3+
cycles one usually uses a local strong pointer or a captured weak pointer instead.
4+
15
This will happen in one of two cases generally:
26

37
1. One uses `weakSelf` but forgot to declare it weak first.
4-
2. One is using `strongSelf`, declared in a block, in another (inside) block.
5-
This changes the delicate balance of the `weakSelf`/`strongSelf` use in the
6-
first block. The retain cycle is avoided there because `strongSelf` is a
7-
local variable to the block. If `strongSelf` is used in the inside block,
8+
9+
Example:
10+
11+
```objectivec
12+
__typeof(self) weakSelf = self;
13+
int (^my_block)(BOOL) = ^(BOOL isTapped) {
14+
__strong __typeof(weakSelf) strongSelf = weakSelf;
15+
return strongSelf->x;
16+
};
17+
```
18+
19+
**Action:** Replace the first line with `__weak __typeof(self) weakSelf = self;`.
20+
21+
22+
2. One is using `strongSelf`, declared in a block, in another inner block.
23+
The retain cycle is avoided in the outer block because `strongSelf` is a
24+
local variable of the block. If `strongSelf` is used in the inner block,
825
then it's not a local variable anymore, but a captured variable.
26+
27+
Example:
28+
29+
```objectivec
30+
__weak __typeof(self) weakSelf = self;
31+
int (^my_block)() = ^() {
32+
__strong typeof(self) strongSelf = weakSelf;
33+
if (strongSelf) {
34+
int (^my_block)() = ^() {
35+
int x = strongSelf->x;
36+
...
37+
};
38+
...
39+
}
40+
...
41+
};
42+
```
43+
44+
In this example, `strongSelf` is a captured variable of the inner block, and this could cause retain cycles.
45+
46+
**Action:** Use a new pointer to self local to the inner block. In the example:
47+
48+
```objectivec
49+
__weak __typeof(self) weakSelf = self;
50+
int (^my_block)() = ^() {
51+
__strong typeof(self) strongSelf = weakSelf;
52+
if (strongSelf) {
53+
int (^my_block)() = ^() {
54+
__typeof(self) innerStrongSelf = weakSelf;
55+
int x = innerStrongSelf->x;
56+
...
57+
};
58+
...
59+
}
60+
...
61+
};
62+
```
63+
64+
Or, to improve readability, move the inner block logic into a separate method.
65+
66+
Another solution could be to copy the instance variable that one needs to access inside the inner block to a local variable, and use the local variable instead:
67+
68+
```objectivec
69+
__weak __typeof(self) weakSelf = self;
70+
int (^my_block)() = ^() {
71+
__strong typeof(self) strongSelf = weakSelf;
72+
if (strongSelf) {
73+
int my_x = strongSelf->x;
74+
int (^my_block)() = ^() {
75+
int x = my_x;
76+
...
77+
};
78+
...
79+
}
80+
...
81+
};
82+
```

website/docs/all-issue-types.md

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,89 @@ See [BUFFER_OVERRUN_L1](#buffer_overrun_l1)
246246

247247
Reported as "Captured strongSelf" by [self-in-block](/docs/next/checker-self-in-block).
248248

249+
This check is about when a strong pointer to `self` is captured in a block.
250+
This could lead to retain cycles or unexpected behavior since to avoid retain
251+
cycles one usually uses a local strong pointer or a captured weak pointer instead.
252+
249253
This will happen in one of two cases generally:
250254

251255
1. One uses `weakSelf` but forgot to declare it weak first.
252-
2. One is using `strongSelf`, declared in a block, in another (inside) block.
253-
This changes the delicate balance of the `weakSelf`/`strongSelf` use in the
254-
first block. The retain cycle is avoided there because `strongSelf` is a
255-
local variable to the block. If `strongSelf` is used in the inside block,
256+
257+
Example:
258+
259+
```objectivec
260+
__typeof(self) weakSelf = self;
261+
int (^my_block)(BOOL) = ^(BOOL isTapped) {
262+
__strong __typeof(weakSelf) strongSelf = weakSelf;
263+
return strongSelf->x;
264+
};
265+
```
266+
267+
**Action:** Replace the first line with `__weak __typeof(self) weakSelf = self;`.
268+
269+
270+
2. One is using `strongSelf`, declared in a block, in another inner block.
271+
The retain cycle is avoided in the outer block because `strongSelf` is a
272+
local variable of the block. If `strongSelf` is used in the inner block,
256273
then it's not a local variable anymore, but a captured variable.
257274
275+
Example:
276+
277+
```objectivec
278+
__weak __typeof(self) weakSelf = self;
279+
int (^my_block)() = ^() {
280+
__strong typeof(self) strongSelf = weakSelf;
281+
if (strongSelf) {
282+
int (^my_block)() = ^() {
283+
int x = strongSelf->x;
284+
...
285+
};
286+
...
287+
}
288+
...
289+
};
290+
```
291+
292+
In this example, `strongSelf` is a captured variable of the inner block, and this could cause retain cycles.
293+
294+
**Action:** Use a new pointer to self local to the inner block. In the example:
295+
296+
```objectivec
297+
__weak __typeof(self) weakSelf = self;
298+
int (^my_block)() = ^() {
299+
__strong typeof(self) strongSelf = weakSelf;
300+
if (strongSelf) {
301+
int (^my_block)() = ^() {
302+
__typeof(self) innerStrongSelf = weakSelf;
303+
int x = innerStrongSelf->x;
304+
...
305+
};
306+
...
307+
}
308+
...
309+
};
310+
```
311+
312+
Or, to improve readability, move the inner block logic into a separate method.
313+
314+
Another solution could be to copy the instance variable that one needs to access inside the inner block to a local variable, and use the local variable instead:
315+
316+
```objectivec
317+
__weak __typeof(self) weakSelf = self;
318+
int (^my_block)() = ^() {
319+
__strong typeof(self) strongSelf = weakSelf;
320+
if (strongSelf) {
321+
int my_x = strongSelf->x;
322+
int (^my_block)() = ^() {
323+
int x = my_x;
324+
...
325+
};
326+
...
327+
}
328+
...
329+
};
330+
```
331+
258332
## CHECKERS_ALLOCATES_MEMORY
259333

260334
Reported as "Allocates Memory" by [annotation-reachability](/docs/next/checker-annotation-reachability).

0 commit comments

Comments
 (0)