我有一个有两个属性的类:
@interface Contact : NSObject {
NSString *lastname;
NSString *lastNameUpper;
}
我已将姓氏声明为属性(并在.m文件中合成):
@property (nonatomic, retain) NSString *lastname;
但是,我想编写自己的方法来访问lastNameUpper,所以我声明了一个方法:
- (NSString *) lastNameUpper;
并像这样实现:
- (NSString *) lastNameUpper {
if (!lastNameUpper) {
lastNameUpper = [lastname uppercaseString];
}
return lastNameUpper;
}
这样可以正常工作,但由于这种情况经常被调用,因此会调用很多临时对象。有趣的是,仪器显示了很多“Malloc(4k)”,并且每次访问lastNameUpper
时数量都会增加。我还可以看到内存是在objc_retailAutoreleaseReturnValue
中分配的。
由于这在我将项目转换为ARC之前工作正常,我假设我必须对方法签名进行一些ARC特定的添加,但我似乎无法使其工作。
有什么建议吗?
答案 0 :(得分:2)
0:你应该复制你的NSString属性:
@property (nonatomic, copy) NSString * lastname;
我猜测返回字符串是通过复制来实现的。
没了。 immutable 字符串的副本是保留操作。只需在分析器中运行它,看看这花费了多少时间和内存。此外,在这种情况下没有隐含的副本。
<强>更新强>
我在Lion-64上测试了这个。 uppercaseString
可能会返回可变字符串。
为安全起见,您可以考虑分配uppercaseString
:lastNameUpper = [[lastname uppercaseString] copy];
的结果副本。这可能导致更多或更少的分配,具体取决于您在实现中使用字符串的方式。如果您的属性复制,则每次分配时都会进行复制。简单的概括是指定一个副本,其余的通常都是自己处理。
测试计划
// ARC enabled
#import <Foundation/Foundation.h>
@interface Contact : NSObject
{
NSString * lastname;
NSString * lastNameUpper;
}
@property (nonatomic, copy) NSString *lastname;
@end
@implementation Contact
@synthesize lastname;
- (NSString *) lastNameUpper {
if (!lastNameUpper) {
lastNameUpper = [lastname uppercaseString];
}
return lastNameUpper;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
int n = 0;
while (n++ < 100000) {
Contact * c = [Contact new];
c.lastname = @"skjdhskjdhaksjhadi";
NSString * lastNameUpper = c.lastNameUpper;
}
}
return 0;
}
答案 1 :(得分:1)
覆盖- (void)setLastname:(NSString*)aLastname
方法(由@synthesize lastname
自动创建,并在现有方法中设置lastNameUpper。
现在创建一个lastNameUpper属性(并合成它):
@property (nonatomic, readonly) NSString *lastNameUpper;
由于这将返回lastNameUpper实例变量的指针,因此无论何时访问它都不应该复制。