@property/@synthesize question

吃可爱长大的小学妹 提交于 2019-12-20 08:56:07

问题


I'm going through all of my documentation regarding memory management and I'm a bit confused about something.

When you use @property, it creates getters/setters for the object:

.h: @property (retain, nonatomic) NSString *myString

.m: @synthesize myString

I understand that, but where I get confused is the use of self. I see different syntax in different blogs and books. I've seen:

myString = [NSString alloc] initWithString:@"Hi there"];

or

self.myString = [NSString alloc] initWithString:@"Hi there"];

Then in dealloc I see:

self.myString = nil;

or

[myString release];

or

self.myString = nil;
[myString release];

On this site, someone stated that using self adds another increment to the retain count? Is that true, I haven't seen that anywhere.

Do the automatic getters/setters that are provided autorelease?

Which is the correct way of doing all of this?

Thanks!


回答1:


If you are not using the dot syntax you are not using any setter or getter.

The next thing is, it depends on how the property has been declared.

Let's assume something like this:

@property (nonatomic, retain) Article *article;
...
@synthesize article;

Assigning something to article with

self.article = [[Article alloc] init];

will overretain the instance given back by alloc/init and cause a leak. This is because the setter of article will retain it and will release any previous instance for you.

So you could rewrite it as:

self.article = [[[Article alloc] init] autorelease];

Doing this

article = [[Article alloc] init]; 

is also ok, but could involve a leak as article may hold a reference to an instance already. So freeing the value beforehand would be needed:

[article release];
article = [[Article alloc] init]; 

Freeing memory could be done with

[article release];

or with

self.article = nil;

The first one does access the field directly, no setters/getters involved. The second one sets nil to the field by using a setter. Which will release the current instance, if there is one before setting it to nil.

This construct

self.myString = nil; 
[myString release];

is just too much, it actually sends release to nil, which is harmless but also needless.

You just have to mentally map hat using the dot syntax is using accessor methods:

self.article = newArticle
// is
[self setArticle:newArticle];

and

myArticle = self.article;
// is
myArticle = [self article];

Some suggestions on reading, all official documents by Apple:

The Objective-C Programming Language

  • Dot Syntax
  • Declared Properties

Memory Management Programming Guide

  • Object Ownership and Disposal
  • Using Accessor Methods



回答2:


When you create a retain setter, you're creating something like this:

- (void)setString:(NSString *)someString {
    if (someString != string) {
        [string release];
        [someString retain];
        string = someString;
    }
}

If you don't use the setter, the new value is not getting that retain—you don't "own" that string, and because it's all references, if the original string is released, you might be facing a null reference, which will lead to an EXC_BAD_ACCESS. Using the setter ensures that your class now has a copy of that value—so yes, it does increment the retain count of the new value. (Note that using the getter is a convention of OOP—that outsiders should not be able to directly touch the ivar. Also in your getter you can modify the value, maybe returning an NSArray when your ivar is an NSMutableArray, for example).

You shouldn't autorelease in a setter—Apple has used it in their sample code, but a thing to keep in mind is that setters are called a lot—millions of times, potentially. All of those objects are going into the same autorelease pool, so unless you create your own and/or regularly flush it, you'll have a ton of elements in your pool, all unneeded but still taking up RAM. Much better to simply release.

As for dealloc, trace back through that setter. If you send a release directly, it's obvious—you release that object. But if you write self.string = nil;, what you're doing is this:

  1. The nil value is not the same, so you enter the if block
  2. You release the old value—what you want to do
  3. You retain nil: messages to nil do nothing, and you don't crash
  4. You set nil, which doesn't take up any memory, to the string, which is now effectively empty

As a matter of convention, I use release in my dealloc method, because release seems more final, and dealloc is the final method call your object will receive. I use self.string = nil; in viewDidUnload and the memory warning methods.

Hope this helps!




回答3:


In addition to Nick's answer - synthesized getters/setters don't provide autorelease (btw, what's the big idea of doing this? Well, you can use getter as a factory, but it's not a common way in Objective C).

Then in dealloc I see:

self.myString = nil;

or

[myString release];

or

self.myString = nil; [myString release];

In dealloc it doesn't really matter which form of release you're using. But the good way is to nil your fields when releasing them :) I prefer to use self.myString = nil; in dealloc



来源:https://stackoverflow.com/questions/5903281/property-synthesize-question

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!