开发者

How to retain my own objects and properties

I'm not sure I understood how alloc and retain work.

Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc

Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.

Here is my way of doing it:

/**** VIEW.h *****/
#import "MyClass.h"
@interface MyViewController : UIViewController  {
      //Is the following line really necessary?
    MyClass *myObject;
}
@property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
@end

.

/**** VIEW.m *****/
#import "VIEW.h"
@implementation MyViewController
@dynamic myObject;

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self defineObject];
    NSLog(@"My object's name is: %@", myObject.name);
}

- (void)defineObject
{
      //Here particularly, Why doesn't it work without both alloc and init
      //shouldn't "@property (nonatomic, retain) MyClass *myObject;" have done that already?
    myObject = [[MyClass alloc] initPersonalised];
    [myObject setName:@"my name"];
}

.

/**** MyClass.h *****/
@interface MyClass : NSObject {
      //not sure if this line is still necessary
    NSString *name;
}

@property (nonatomic, retain) NSString *name;

- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;

@end

.

/**** MyClass.m *****/
#import "MyClass.h"
@implementation MyClass

@dynamic name;

(id)initPersonalised{   
    self = [super init];
    name = @"Undefined";
}
- (void)setName:(NSString *)name{
    self.name = [name copy];
}

- (NSString *)name{
    return [self.name copy];
}

@end
开发者_如何学C

I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.


This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:

Instance variable vs. property access

Within MyViewController,

myObject = xxx;

and

self.myObject = xxx;

are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.

Deallocation

Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:

-(void) dealloc {
  [myObject release];
  [super dealloc];
}

Now to your code:

The snippet:

myObject = [[MyClass alloc] initPersonalised];

is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.

In MyClass you could use @synthesize name instead of @dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.

Finally, your missing dealloc.

Update:

If you use:

self.myObject = [[MyClass alloc] initPersonalised];

then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:

MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];

It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:

self.name = [NSString stringWithFormat: @"instance %d", cnt];

If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:

@property (nonatomic, copy) NSString *name;

When you then use @synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.

And NSString *name; is necessary even if you use @property and/or @synthesize to implement the property.


Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.

Now, to answer the questions I found in your code.

   @interface MyViewController : UIViewController  {
      //Is the following line really necessary?
    MyClass *myObject;
}

So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.

- (void)defineObject
{
      //Here particularly, Why doesn't it work without both alloc and init
      //shouldn't "@property (nonatomic, retain) MyClass *myObject;" have done that already?
    myObject = [[MyClass alloc] initPersonalised];
    [myObject setName:@"my name"];
}

Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.

In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.

All in all, this is what I recommend you to study a bit more:

  • Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
  • iOS Memory Management.


You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜