问题描述
使用 alloc
或 autorelease
初始化程序更好(更快,更高效)。例如:
- (NSString *)hello:(NSString *)name {
return [[NSString alloc] initWithFormat :@Hello,%@,name];
}
或
- (NSString *)hello:(NSString *)name {
return [NSString stringWithFormat:@Hello,%@,name];
// return [@Hello,stringByAppendingString:name]; //甚至更简单
}
我知道在大多数情况下,物。但是,我仍然想要做更好的方式的习惯。
如果他们做同样的事情,那么我更喜欢后一个选项,因为它更短的类型和更可读。
在Xcode 4.2中,有一种方法看看ARC编译,即,它放置 / code>,
release
, autorelease
此功能在切换到ARC时非常有用。我知道你不应该考虑这些东西,但它会帮助我找出这样的问题的答案。
区别很微妙,但您应该选择 autorelease
版本。首先,你的代码更加可读。其次,在检查优化的汇编输出时, autorelease
版本稍微更优化。
$ c> autorelease 版本,
- (NSString *)hello:
return [NSString stringWithFormat:@Hello,%@,name];
}
翻译为
- [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}
如下:
- [SGCAppDelegate hello:]:
pre>
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- 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暂时保留名称字符串
mov r1,r5
mov r4,r0
mov r0,r6
blx _objc_msgSend;调用alloc
movw r1,:lower16:(L_OBJC_SELECTOR_REFERENCES_4-(LPC1_2 + 4))
mov r3,r4
movt r1,:upper16:(L_OBJC_SELECTOR_REFERENCES_4- b $ b 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;调用initWithFormat:
mov r5,r0
mov r0,r4
blx _objc_release; ARC释放名称string
mov r0,r5
pop.w {r4,r5,r6,r7,lr}
bw _objc_autorelease
正如预期,它是一个更长的时间,因为它正在调用
alloc
和initWithFormat:
方法。特别有趣的是,ARC在这里生成次优代码,因为它保留了name
字符串(通过调用_objc_retain标注),并且稍后在调用initWithFormat:
。
如果我们添加
__ unsafe_unretained
所有权限定符,如下面的示例所示,代码将被最佳地呈现。__ unsafe_unretained
指示编译器使用原语(复制指针)。- (NSString *)hello:(__ unsafe_unretained NSString *)name {
return [[NSString alloc] initWithFormat:@Hello,%@,name];
}
,如下所示:
- [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}
bw _objc_autorelease
Is it better (faster & more efficient) to use
alloc
orautorelease
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]; // even simpler }
I know that in most cases, performance here shouldn't matter. But, I'd still like to get in the habit of doing it the better way.
If they do exactly the same thing, then I prefer the latter option because it's shorter to type and more readable.
In Xcode 4.2, is there a way to see what ARC compiles to, i.e., where it puts
retain
,release
,autorelease
, etc? This feature would be very useful while switching over to ARC. I know you shouldn't have to think about this stuff, but it'd help me figure out the answer to questions like these.解决方案The difference is subtle, but you should opt for the
autorelease
versions. Firstly, your code is much more readable. Secondly, on inspection of the optimized assembly output, theautorelease
version is slightly 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 the [[alloc] init] version looks like the 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 the name string temporarily mov r1, r5 mov r4, r0 mov r0, r6 blx _objc_msgSend ; call to 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 to initWithFormat: mov r5, r0 mov r0, r4 blx _objc_release ; ARC releases the name string mov r0, r5 pop.w {r4, r5, r6, r7, lr} b.w _objc_autorelease
As expected, it is a little longer, because it is calling the
alloc
andinitWithFormat:
methods. What is particularly interesting is ARC is generating sub-optimal code here, as it retains thename
string (noted by call to _objc_retain) and later released after the call toinitWithFormat:
.If we add the
__unsafe_unretained
ownership qualifier, as in the following example, the code is rendered optimally.__unsafe_unretained
indicates to the compiler to 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
这篇关于使用ARC,更好的是:alloc或autorelease initializers?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!