I have read the Transitioning to ARC Release Notes in “Summary” Section. They told :
ARC works by adding code at compile time to ensure that objects live
as long as necessary, but no longer. Conceptually, it follows the same
memory management conventions as manual reference counting (described
in Advanced Memory Management Programming Guide) by adding the
appropriate memory management calls for you.In order for the compiler to generate correct code
I wonder what result that ARC corrected our code.
My question : Can we see the change? (In the term of alloc , retain , assign or release .Not assembly level !)
Reason : Because I think It’s good to see the best-practice code in the old tradition development without ARC mode.
ARC in clang doesn’t work by rewriting code from ObjC to ObjC, but emitting the extra retain/release LLVM bitcode during code-gen. That means, it is not possible to know how the compiler “fix” it without going to LLVM IR / assembly level.
It is always better if the compiler can reduce the number of passes through the code.
To get the assembly code, you could either
Generate assembly directly from the compiler. In the command line, add the
-Sflag when invoking the compiler. The result is a.Sfile containing the assembly code. In an Xcode project, open the source code file, then go to Product (on menu bar) → Generate Output → Assembly File.Generate the object file, and then disassemble it. The built-in command
otool -tvV <file>can perform disassembly, and there are advanced tools like otx (free) or IDA (free for evaluation).I prefer route 2 because it generates less garbage and the disassembly tool can be configured to produce more useful information. Anyway, with either method you need to be able to read assembly code.
Take this code as example:
After compiling the following assembly will be produced (analyzed using IDA):
-[SomeAppDelegate application:didFinishLaunchingWithOptions:]: push {r4-r7,lr} add r7, sp, #0xC str.w r8, [sp,-#0x4]! sub sp, sp, #0x18 movw r1, #(0x343c - 0x2574) ; @selector(alloc) mov r8, r0 movt.w r1, #0 mov r0, (0x3464 - 0x2576) ; _OBJC_CLASS_$_UIWindow add r1, pc add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend mov r1, (0x3440 - 0x258e) ; @selector(mainScreen) mov r6, r0 movw r0, #(0x3468 - 0x2594) ; _OBJC_CLASS_$_UIScreen add r1, pc movt.w r0, #0 add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend mov r7, r7 blx _objc_retainAutoreleasedReturnValue mov r5, r0 cbz r5, L25ba movw r0, #(0x3444 - 0x25b2) ; @selector(bounds) mov r1, r5 movt.w r0, #0 add r0, pc ldr r2, [r0] add r0, sp, #0x8 blx _objc_msgSend_stret b L25c4 L25ba: add r0, sp, #0x8 vmov.i32 q8, #0x80 vstmia r0, {d16-d17} L25c4: mov r1, (0x3448 - 0x25d2) ; @selector(initWithFrame:) ldr r0, [sp,#0x10] add r1, pc ldr r2, [sp,#0x8] ldr r3, [sp,#0xc] ldr r4, [sp,#0x14] stmea.w sp, {r0,r4} mov r0, r6 ldr r1, [r1] blx _objc_msgSend mov r4, r0 mov r0, (0x344c - 0x25F2) ; @selector(setWindow:) mov r2, r4 add r0, pc ldr r1, [r0] mov r0, r8 blx _objc_msgSend mov r0, r4 blx _objc_release mov r0, r5 blx _objc_release mov r0, (0x3450 - 0x2610) ; @selector(window) add r0, pc ldr r5, [r0] mov r0, r8 mov r1, r5 blx _objc_msgSend mov r7, r7 blx _objc_retainAutoreleasedReturnValue mov r1, (0x3454 - 0x2630) ; @selector(whiteColor) mov r6, r0 movw r0, #(0x346C - 0x2636) ; _OBJC_CLASS_$_UIColor add r1, pc movt.w r0, #0 add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend mov r7, r7 blx _objc_retainAutoreleasedReturnValue mov r4, r0 mov r0, (0x3458 - 0x2652) ; @selector(setBackgroundColor:) mov r2, r4 add r0, pc ldr r1, [r0] mov r0, r6 blx _objc_msgSend mov r0, r4 blx _objc_release mov r0, r6 blx _objc_release mov r0, r8 mov r1, r5 blx _objc_msgSend mov r7, r7 blx _objc_retainAutoreleasedReturnValue mov r4, r0 mov r0, (0x345C - 0x2680) ; @selector(makeKeyAndVisible) add r0, pc ldr r1, [r0] mov r0, r4 blx _objc_msgSend mov r0, r4 blx _objc_release movs r0, #1 add sp, sp, #0x18 ldr.w r8, [sp], #4 pop {r4-r7,pc}Without going into detail, you can see there are many
_objc_releaseand_objc_retainAutoreleasedReturnValue. These are what ARC inserts during code-gen. Decompiling it by hand, we’ll get:which is just the same as what @c roald‘s link describes.