0

我有一个具有两个属性的类:

@interface Contact : NSObject {
    NSString *lastname;
    NSString *lastNameUpper;
}

我已经将 lastname 声明为一个属性(并在 .m 文件中合成它):

@property (nonatomic, retain) NSString *lastname;

但是,我想编写自己的方法来访问 lastNameUpper,所以我声明了一个方法:

- (NSString *) lastNameUpper;

并像这样实现它:

- (NSString *) lastNameUpper {
    if (!lastNameUpper) {
        lastNameUpper = [lastname uppercaseString];
    }
    return lastNameUpper;
}

这可以正常工作,但是由于它经常被调用,所以会调用很多临时对象。有趣的是,Instruments 显示很多“Malloc (4k)”,每次lastNameUpper访问次数都增加。我还可以看到内存分配在objc_retailAutoreleaseReturnValue.

由于在我将项目转换为 ARC 之前这工作正常,我假设我必须对方法签名进行一些 ARC 特定的添加,但我似乎无法使其工作。

有什么建议么?

4

2 回答 2

2

0:你应该复制你的 NSString 属性:

 @property (nonatomic, copy) NSString * lastname;

我猜返回字符串是通过复制来实现的。

不。不可变字符串的副本是保留操作。只需在分析器中运行它,看看这在时间和内存上的成本是多少。此外,在这种情况下没有隐式副本。

更新

我在 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;
}
于 2012-04-20T16:14:54.140 回答
1

覆盖- (void)setLastname:(NSString*)aLastname方法(由 自动创建@synthesize lastname,并将 lastNameUpper 设置为现有方法。

现在创建一个 lastNameUpper 属性(并合成它):

@property (nonatomic, readonly) NSString *lastNameUpper;

由于这将返回 lastNameUpper 实例变量的指针,因此无论何时访问它都不应进行复制。

于 2012-04-20T16:13:54.777 回答