objective c - With ARC, what's better: alloc or autorelease initializers? -
is better (faster & more efficient) use alloc
or autorelease
initializers. e.g.:
- (nsstring *)hello:(nsstring *)name { return [[nsstring alloc] initwithformat:@"hello, %@", name]; }
or
- (nsstring *)hello:(nsstring *)name { return [nsstring stringwithformat:@"hello, %@", name]; // return [@"hello, " stringbyappendingstring:name]; // simpler }
i know in cases, performance here shouldn't matter. but, i'd still in habit of doing better way.
if same thing, prefer latter option because it's shorter type , more readable.
in xcode 4.2, there way see arc compiles to, i.e., puts retain
, release
, autorelease
, etc? feature useful while switching on arc. know shouldn't have think stuff, it'd me figure out answer questions these.
the difference subtle, should opt autorelease
versions. firstly, code more readable. secondly, on inspection of optimized assembly output, autorelease
version more optimal.
the autorelease
version,
- (nsstring *)hello:(nsstring *)name { return [nsstring stringwithformat:@"hello, %@", name]; }
translates to
"-[sgcappdelegate hello:]": push {r7, lr} movw r1, :lower16:(l_objc_selector_references_-(lpc0_0+4)) mov r3, r2 movt r1, :upper16:(l_objc_selector_references_-(lpc0_0+4)) movw r0, :lower16:(l_objc_classlist_references_$_-(lpc0_1+4)) movt r0, :upper16:(l_objc_classlist_references_$_-(lpc0_1+4)) add r1, pc add r0, pc mov r7, sp ldr r1, [r1] ldr r0, [r0] movw r2, :lower16:(l__unnamed_cfstring_-(lpc0_2+4)) movt r2, :upper16:(l__unnamed_cfstring_-(lpc0_2+4)) add r2, pc blx _objc_msgsend ; stringwithformat: pop {r7, pc}
whereas [[alloc] init] version looks following:
"-[sgcappdelegate hello:]": push {r4, r5, r6, r7, lr} movw r1, :lower16:(l_objc_selector_references_2-(lpc1_0+4)) add r7, sp, #12 movt r1, :upper16:(l_objc_selector_references_2-(lpc1_0+4)) movw r0, :lower16:(l_objc_classlist_references_$_-(lpc1_1+4)) movt r0, :upper16:(l_objc_classlist_references_$_-(lpc1_1+4)) add r1, pc add r0, pc ldr r5, [r1] ldr r6, [r0] mov r0, r2 blx _objc_retain ; arc retains name string temporarily mov r1, r5 mov r4, r0 mov r0, r6 blx _objc_msgsend ; call alloc movw r1, :lower16:(l_objc_selector_references_4-(lpc1_2+4)) mov r3, r4 movt r1, :upper16:(l_objc_selector_references_4-(lpc1_2+4)) add r1, pc ldr r1, [r1] movw r2, :lower16:(l__unnamed_cfstring_-(lpc1_3+4)) movt r2, :upper16:(l__unnamed_cfstring_-(lpc1_3+4)) add r2, pc blx _objc_msgsend ; call initwithformat: mov r5, r0 mov r0, r4 blx _objc_release ; arc releases name string mov r0, r5 pop.w {r4, r5, r6, r7, lr} b.w _objc_autorelease
as expected, little longer, because calling alloc
, initwithformat:
methods. particularly interesting arc generating sub-optimal code here, retains name
string (noted call _objc_retain) , later released after call initwithformat:
.
if add __unsafe_unretained
ownership qualifier, in following example, code rendered optimally. __unsafe_unretained
indicates compiler use primitive (copy pointer) assignment semantics.
- (nsstring *)hello:(__unsafe_unretained nsstring *)name { return [[nsstring alloc] initwithformat:@"hello, %@", name]; }
as follows:
"-[sgcappdelegate hello:]": push {r4, r7, lr} movw r1, :lower16:(l_objc_selector_references_2-(lpc1_0+4)) add r7, sp, #4 movt r1, :upper16:(l_objc_selector_references_2-(lpc1_0+4)) movw r0, :lower16:(l_objc_classlist_references_$_-(lpc1_1+4)) movt r0, :upper16:(l_objc_classlist_references_$_-(lpc1_1+4)) add r1, pc add r0, pc mov r4, r2 ldr r1, [r1] ldr r0, [r0] blx _objc_msgsend movw r1, :lower16:(l_objc_selector_references_4-(lpc1_2+4)) mov r3, r4 movt r1, :upper16:(l_objc_selector_references_4-(lpc1_2+4)) add r1, pc ldr r1, [r1] movw r2, :lower16:(l__unnamed_cfstring_-(lpc1_3+4)) movt r2, :upper16:(l__unnamed_cfstring_-(lpc1_3+4)) add r2, pc blx _objc_msgsend .loc 1 31 1 pop.w {r4, r7, lr} b.w _objc_autorelease
Comments
Post a Comment