ARC в clang не работает, переписывая код из ObjC в ObjC, но выдавая дополнительный бит LLVM сохранения/выпуска во время кода-gen. Это означает, что невозможно понять, как компилятор «исправит» его, не перейдя на уровень LLVM IR/assembly.
Если АРК испускает LLVM, как битовый код вы сказали. Это сделано для этой цели, которая использует меньше времени в процессе компиляции? (менее сложный код ObjC, меньше заголовочный файл?)
Всегда лучше, если компилятор может уменьшить количество проходов через код.
Можете ли вы показать мне пример или утилиты, которые показывают код на уровне сборки?
Чтобы получить код сборки, вы можете либо
Сформировать сборку непосредственно от компилятора. В командной строке добавьте флаг -S
при вызове компилятора. Результатом является файл .S
, содержащий код сборки. В проекте Xcode откройте файл исходного кода, затем перейдите к . Продукт (в строке меню) → Создать выход → Сборочный файл.
Сгенерировать файл объекта, а затем разобрать его. Встроенная команда otool -tvV <file>
может выполнить разборку, и есть дополнительные инструменты, такие как otx (бесплатно) или IDA (бесплатно для оценки).
Я предпочитаю маршрут 2, потому что он генерирует меньше мусора, и инструмент разборки может быть сконфигурирован для получения более полезной информации.В любом случае, с помощью любого метода вам нужно будет прочитать код сборки.
Возьмите этот код, например:
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
После компиляции следующей сборки будет производиться (анализировались с помощью 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}
Не вдаваясь в подробности, вы можете видеть, что есть много _objc_release
и _objc_retainAutoreleasedReturnValue
. Это то, что ARC вставляет в код-gen. Декомпиляция его вручную, мы получим:
UIScreen* r5 = objc_retainAutoreleasedReturnValue([UIScreen mainScreen]);
CGRect sp8 = r5 != nil ? [r5 bounds] : CGRectZero;
UIWindow* r4 = [[UIWindow alloc] initWithFrame:sp8];
[self setWindow:r4];
objc_release(r4);
objc_release(r5);
UIWindow* r6a = objc_retainAutoreleasedReturnValue([self window])
UIColor* r4a = objc_retainAutoreleasedReturnValue([UIColor whiteColor])
[r6a setBackgroundColor:r4a];
objc_release(r4a);
objc_release(r6a);
UIWindow* r4b = objc_retainAutoreleasedReturnValue([self window])
[r4b makeKeyAndVisible];
objc_release(r4b);
return 1;
, который так же, как то, что описывает ссылку @c roald «s.
Для исследования, я имею в виду «развитие старой традиции», это о том, как мы можем правильно распределять, сохранять, назначать или выпускать их. Я также не хотел бы жестко кодировать детали сборки :-). – Sakares
Вы можете просто прочитать документацию, связанную со статьей, которую вы цитируете, ARC делает то же самое, что описано в этой статье. Прочтите раздел «Политика управления памятью», чтобы начать, большинство правил ARC для ежедневного программирования получены оттуда. https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html –
Возможный дубликат [Просмотр, где ARC вставляет сохранение и релизы] (http://stackoverflow.com/questions/8812098/see-where-arc-is-inserting-retain-and-releases) –