Is there any performance gain if I write
- (NSString *)helloStringWithName:(NSString *)name
static NSString *formatString = @"Hello %@!";
return [NSString stringWithFormat:formatString, name];
}
instead of
- (NSString *)helloStringWithName:(NSString *)name
return [NSString stringWithFormat:@"Hello %@!", name];
}
??
If I were to guess I would think that the latter one is created and autoreleased each time the code is running, but I guess the compiler is smart enough to know what do here..
If you try this out (Menu->Product->Generate Output->Assembly File) - you'll note virtually identical output under clang - with only small changes due to the extra variable assignment & debugging info left.
So in short - no real difference; though the static one may be a bit easier to debug I guess.
.align 4, 0x90
"-[Foo helloStringWithName1:]": ## @"\01-[Foo helloStringWithName1:]"
.cfi_startproc
Lfunc_begin0:
.loc 1 15 0 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:15:0
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
subq $48, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, %rdi
callq _objc_retain
movq %rax, -24(%rbp)
.loc 1 17 5 prologue_end ## /Users/dirkx/tmp/ccccc/ccccc/main.m:17:5
Ltmp5:
movq L_OBJC_CLASSLIST_REFERENCES_$_(%rip), %rax
movq "-[Foo helloStringWithName1:].formatString"(%rip), %rdx
movq -24(%rbp), %rcx
movq L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
movq %rax, %rdi
movb $0, %al
callq _objc_msgSend
movq %rax, %rdi
callq _objc_retainAutoreleasedReturnValue
movabsq $0, %rsi
leaq -24(%rbp), %rcx
movl $1, -28(%rbp)
.loc 1 18 1 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:18:1
movq %rcx, %rdi
movq %rax, -40(%rbp) ## 8-byte Spill
callq _objc_storeStrong
Ltmp6:
.loc 1 18 1 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:18:1
movq -40(%rbp), %rax ## 8-byte Reload
movq %rax, %rdi
callq _objc_autoreleaseReturnValue
.loc 1 17 5 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:17:5
Ltmp7:
addq $48, %rsp
popq %rbp
ret
Ltmp8:
Lfunc_end0:
.cfi_endproc
versus
.align 4, 0x90
"-[Foo helloStringWithName2:]": ## @"\01-[Foo helloStringWithName2:]"
.cfi_startproc
Lfunc_begin1:
.loc 1 20 0 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:20:0
## BB#0:
pushq %rbp
Ltmp11:
.cfi_def_cfa_offset 16
Ltmp12:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp13:
.cfi_def_cfa_register %rbp
subq $48, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, %rdi
callq _objc_retain
leaq L__unnamed_cfstring_2(%rip), %rdx <--------------------
movq %rax, -24(%rbp)
.loc 1 21 5 prologue_end ## /Users/dirkx/tmp/ccccc/ccccc/main.m:21:5
Ltmp14:
movq L_OBJC_CLASSLIST_REFERENCES_$_(%rip), %rax
movq -24(%rbp), %rcx
movq L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
movq %rax, %rdi
movb $0, %al
callq _objc_msgSend
movq %rax, %rdi
callq _objc_retainAutoreleasedReturnValue
movabsq $0, %rsi
leaq -24(%rbp), %rcx
movl $1, -28(%rbp)
.loc 1 22 1 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:22:1
movq %rcx, %rdi
movq %rax, -40(%rbp) ## 8-byte Spill
callq _objc_storeStrong
Ltmp15:
.loc 1 22 1 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:22:1
movq -40(%rbp), %rax ## 8-byte Reload
movq %rax, %rdi
callq _objc_autoreleaseReturnValue
.loc 1 21 5 ## /Users/dirkx/tmp/ccccc/ccccc/main.m:21:5
Ltmp16:
addq $48, %rsp
popq %rbp
ret
Ltmp17:
Lfunc_end1:
.cfi_endproc
with as key references:
Lfunc_end2:
.cfi_endproc
.section __DATA,__data
.align 3 ## @"\01-[Foo helloStringWithName1:].formatString"
"-[Foo helloStringWithName1:].formatString":
.quad L__unnamed_cfstring_
.section __TEXT,__cstring,cstring_literals
l_.str: ## @.str
.asciz "Hello 1 %@!"
and
.section __TEXT,__cstring,cstring_literals
l_.str1: ## @.str1
.asciz "Hello 2 %@!"
String literals in Objective-C are allocated at compile time, therefore you won't reasonably gain anything in performance.
Considers this
NSString * str = @"Hello";
NSString * str2 = @"Hello";
NSLog(@"%p", str); // => 0x860358
NSLog(@"%p", str2); // => 0x860358
Therefore if your intent is to say something like:
"Hey compiler, the format string is always the same so don't bother allocating that more than once"
the answer would be:
"How nice, tell me something I don't know"
NOTE
If you are still skeptical you can take a look at the assembly (check out Dirk's answer), but let me give you a piece of advice here: don't bang your head against such performance issues.
The overhead of using NSString
and a high level abstraction as objects in general is definitely predominant in your program performances, so even if you gain a nanosecond per string, you won't reasonably even notice that.
And as you rightfully suspect, the compiler is already smart enough to take care of such details.
To wrap it up: let the compiler do its job and you do yours, i.e. writing readable and maintainable code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With