NSString - статический или встроенный? Есть ли выигрыш в производительности?
Есть ли увеличение производительности, если я пишу
- (NSString *)helloStringWithName:(NSString *)name
static NSString *formatString = @"Hello %@!";
return [NSString stringWithFormat:formatString, name];
}
вместо
- (NSString *)helloStringWithName:(NSString *)name
return [NSString stringWithFormat:@"Hello %@!", name];
}
??
Если бы я предполагал, что я думаю, что последний создается и автореализован каждый раз, когда выполняется код, но я думаю, что компилятор достаточно умен, чтобы знать, что здесь делать.
Ответы
Ответ 1
Строковые литералы в Objective-C выделяются во время компиляции, поэтому вы не сможете получить что-либо в производительности.
Рассматривает это
NSString * str = @"Hello";
NSString * str2 = @"Hello";
NSLog(@"%p", str); // => 0x860358
NSLog(@"%p", str2); // => 0x860358
Поэтому, если вы намерены сказать что-то вроде:
"Привет, компилятор, строка формата всегда одна и та же, поэтому не беспокойтесь о том, чтобы выделить это более одного раза"
ответ будет следующим:
"Как хорошо, скажи мне, что я не знаю"
Примечание
Если вы все еще настроены скептически, вы можете взглянуть на сборку (проверьте ответ Дирка), но позвольте мне дать вам несколько советов: не ударяйте головой о таких проблемах с производительностью.
Накладные расходы на использование NSString
и абстракция высокого уровня в качестве объектов в целом определенно преобладают в ваших программах, поэтому, даже если вы наберете наносекунду на строку, вы не сможете это даже заметить.
И, как вы по праву подозреваете, компилятор уже достаточно умен, чтобы заботиться о таких деталях.
Завершить это: пусть компилятор выполнит свою работу, и вы сделаете свое, то есть написали читаемый и поддерживаемый код.
Ответ 2
Если вы попробуете это (Menu- > Product- > Generate Output- > Assembly File), вы увидите практически идентичный вывод под clang - с небольшими изменениями из-за дополнительной информации о параметрах и информации об отставке.
Итак, короче - никакой реальной разницы; хотя статический, возможно, немного легче отлаживать, я думаю.
.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
против
.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
с ключевыми ссылками:
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 %@!"
и
.section __TEXT,__cstring,cstring_literals
l_.str1: ## @.str1
.asciz "Hello 2 %@!"