在ARC下返回NSString时如何避免临时对象

时间:2023-01-04 09:44:41

I've got a class with two properties:

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

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

I've declared lastname as a property (and synthesize it in the .m-file):

我已将姓氏声明为属性(并在.m文件中合成):

@property (nonatomic, retain) NSString *lastname;

However, I want to write my own method to access the lastNameUpper, so I declared a method:

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

- (NSString *) lastNameUpper;

and implemented it like this:

并像这样实现:

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

This works all right, but as this is called quite often, a lot of temporary objects are called. Interestingly, the Instruments show a lot of "Malloc (4k)", and the number increase each time lastNameUpper is accessed. I can also see that the memory is allocated in objc_retailAutoreleaseReturnValue.

这样可以正常工作,但由于经常调用它,因此会调用许多临时对象。有趣的是,仪器显示了很多“Malloc(4k)”,并且每次访问lastNameUpper时数量都会增加。我还可以看到内存是在objc_retailAutoreleaseReturnValue中分配的。

As this was working fine before I converted my project to ARC, I'm assuming that I have to make some ARC specific additions to the method signature, but I can't seem to be able to make it work.

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

Any suggestions?

2 个解决方案

#1


1  

Override the - (void)setLastname:(NSString*)aLastname method (created automatically by @synthesize lastname, and set lastNameUpper as in the existing method.

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

Now create a lastNameUpper property (and synthesize it):

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

@property (nonatomic, readonly) NSString *lastNameUpper;

Since this will return the pointer of the lastNameUpper instance variable, no copies should be made whenever this is accessed.

由于这将返回lastNameUpper实例变量的指针,因此无论何时访问它都不应该生成副本。

#2


2  

0: you should copy your NSString properties:

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

 @property (nonatomic, copy) NSString * lastname;

I'm guessing that returning the string is implemented by copying it.

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

nope. copy of an immutable string is a retain operation. just run it in the profiler to see how much this costs in time and memory. also, there's no implicit copy in this case.

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

Update

I tested this on Lion-64. uppercaseString may return a mutable string.

我在Lion-64上测试了这个。 uppercaseString可以返回一个可变字符串。

To be safe, you may consider assigning a copy of the result of uppercaseString: lastNameUpper = [[lastname uppercaseString] copy];. that may result in more or less allocations, depending on how you used the string in your implementation. if your properties copy, then a copy will be made each time you assign it. the easy generalization is to assign a copy, and the rest usually takes care of itself.

为安全起见,您可以考虑分配uppercaseString结果的副本:lastNameUpper = [[lastname uppercaseString] copy] ;.这可能导致更多或更少的分配,具体取决于您在实现中使用字符串的方式。如果您的属性复制,则每次分配时都会进行复制。简单的概括是指定一个副本,其余的通常会自行处理。

Test Program

// 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  

Override the - (void)setLastname:(NSString*)aLastname method (created automatically by @synthesize lastname, and set lastNameUpper as in the existing method.

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

Now create a lastNameUpper property (and synthesize it):

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

@property (nonatomic, readonly) NSString *lastNameUpper;

Since this will return the pointer of the lastNameUpper instance variable, no copies should be made whenever this is accessed.

由于这将返回lastNameUpper实例变量的指针,因此无论何时访问它都不应该生成副本。

#2


2  

0: you should copy your NSString properties:

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

 @property (nonatomic, copy) NSString * lastname;

I'm guessing that returning the string is implemented by copying it.

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

nope. copy of an immutable string is a retain operation. just run it in the profiler to see how much this costs in time and memory. also, there's no implicit copy in this case.

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

Update

I tested this on Lion-64. uppercaseString may return a mutable string.

我在Lion-64上测试了这个。 uppercaseString可以返回一个可变字符串。

To be safe, you may consider assigning a copy of the result of uppercaseString: lastNameUpper = [[lastname uppercaseString] copy];. that may result in more or less allocations, depending on how you used the string in your implementation. if your properties copy, then a copy will be made each time you assign it. the easy generalization is to assign a copy, and the rest usually takes care of itself.

为安全起见,您可以考虑分配uppercaseString结果的副本:lastNameUpper = [[lastname uppercaseString] copy] ;.这可能导致更多或更少的分配,具体取决于您在实现中使用字符串的方式。如果您的属性复制,则每次分配时都会进行复制。简单的概括是指定一个副本,其余的通常会自行处理。

Test Program

// 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;
}