结论:在大量重复使用__weak修饰的变量时,把__weak修饰的变量赋值给__strong修饰的变量更好。
在每次使用__weak修饰变量时,编译器都会创建"objc_loadWeakRetained/objc_release"方法。比如下面示例代码:
NSObject *obj = [[NSObject alloc] init];
{
id __weak obj1 = obj;
NSLog(@"%@", obj1);
NSLog(@"%@", obj1);
}
在创建obj处打断点,查看汇编结果:
0x104346598 <+200>: bl 0x104346a90 ; symbol stub for: objc_initWeak
0x10434659c <+204>: ldr x8, [sp, #0x30]
0x1043465a0 <+208>: str x0, [sp, #0x28]
0x1043465a4 <+212>: mov x0, x8
0x1043465a8 <+216>: bl 0x104346a9c ; symbol stub for: objc_loadWeakRetained
0x1043465ac <+220>: mov x1, x0
0x1043465b0 <+224>: mov x8, sp
0x1043465b4 <+228>: str x0, [x8]
0x1043465b8 <+232>: adrp x0, 2
0x1043465bc <+236>: add x0, x0, #0x98 ; =0x98
0x1043465c0 <+240>: str x1, [sp, #0x20]
0x1043465c4 <+244>: bl 0x104346a30 ; symbol stub for: NSLog
0x1043465c8 <+248>: b 0x1043465cc ; <+252> at ViewController.m:36
0x1043465cc <+252>: ldr x0, [sp, #0x20]
0x1043465d0 <+256>: bl 0x104346ac0 ; symbol stub for: objc_release
0x1043465d4 <+260>: sub x0, x29, #0x40 ; =0x40
0x1043465d8 <+264>: bl 0x104346a9c ; symbol stub for: objc_loadWeakRetained
0x1043465dc <+268>: mov x30, x0
0x1043465e0 <+272>: mov x8, sp
0x1043465e4 <+276>: str x0, [x8]
0x1043465e8 <+280>: adrp x0, 2
0x1043465ec <+284>: add x0, x0, #0x98 ; =0x98
0x1043465f0 <+288>: str x30, [sp, #0x18]
0x1043465f4 <+292>: bl 0x104346a30 ; symbol stub for: NSLog
0x1043465f8 <+296>: b 0x1043465fc ; <+300> at ViewController.m:37
0x1043465fc <+300>: ldr x0, [sp, #0x18]
0x104346600 <+304>: bl 0x104346ac0 ; symbol stub for: objc_release
0x104346604 <+308>: sub x0, x29, #0x40 ; =0x40
0x104346608 <+312>: bl 0x104346a84 ; symbol stub for: objc_destroyWeak
第一行调用objc_initWeak方法创建__weak修饰的变量obj1,下面我们使用了obj1变量进行了两次打印,可以看到每次打印之前调用了函数"objc_loadWeakRetained",打印之后又调用了函数"objc_release"。所以需要将__weak修饰变量转化为__strong修饰变量来减少编译器插入的"objc_loadWeakRetained/objc_release"函数对。
下面是将__weak转换为__strong的示例代码:
NSObject *obj = [[NSObject alloc] init];
id __weak obj1 = obj;
{
id __strong obj2 = obj1;
NSLog(@"1 %@", obj2);
NSLog(@"2 %@", obj2);
}
编译结果为:
0x10fe7058d <+189>: call 0x10fe70994 ; symbol stub for: objc_initWeak
0x10fe70592 <+194>: mov rdi, qword ptr [rbp - 0x78]
0x10fe70596 <+198>: mov qword ptr [rbp - 0x80], rax
0x10fe7059a <+202>: call 0x10fe7099a ; symbol stub for: objc_loadWeakRetained
0x10fe7059f <+207>: mov qword ptr [rbp - 0x48], rax
0x10fe705a3 <+211>: mov rsi, qword ptr [rbp - 0x48]
0x10fe705a7 <+215>: lea rdi, [rip + 0x1af2] ; @"1 %@"
0x10fe705ae <+222>: xor ecx, ecx
0x10fe705b0 <+224>: mov dl, cl
0x10fe705b2 <+226>: mov al, dl
0x10fe705b4 <+228>: call 0x10fe70964 ; symbol stub for: NSLog
0x10fe705b9 <+233>: jmp 0x10fe705be ; <+238> at ViewController.m:38
0x10fe705be <+238>: mov rsi, qword ptr [rbp - 0x48]
0x10fe705c2 <+242>: lea rdi, [rip + 0x1af7] ; @"2 %@"
0x10fe705c9 <+249>: xor eax, eax
0x10fe705cb <+251>: mov cl, al
0x10fe705cd <+253>: mov al, cl
0x10fe705cf <+255>: call 0x10fe70964 ; symbol stub for: NSLog
0x10fe705d4 <+260>: jmp 0x10fe705d9 ; <+265> at ViewController.m
0x10fe705d9 <+265>: lea rdi, [rbp - 0x48]
0x10fe705dd <+269>: xor eax, eax
0x10fe705df <+271>: mov esi, eax
0x10fe705e1 <+273>: call 0x10fe709b8 ; symbol stub for: objc_storeStrong
0x10fe705e6 <+278>: lea rdi, [rbp - 0x40]
0x10fe705ea <+282>: call 0x10fe7098e ; symbol stub for: objc_destroyWeak
可以看到"objc_loadWeakRetained"方法只在最开始因为“id __strong obj2 = obj1;”操作而插入了一次,在下面打印过程中再也没有调用过。