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
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,
and
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:
Now to your code:
The snippet:
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 nameinstead of@dynamic. Then the compiler would implementnameandsetName:automatically and you wouldn’t need to do it yourself.Finally, your missing
dealloc.Update:
If you use:
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:
It would be different if you weren’t using
initXXXto create a new instance. The class NSString for example has many methods calledstringXXX, 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: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:
When you then use
@synthesizeto implement the getter and setter, the compiler will generate them using copy instead of retain.And
NSString *name;is necessary even if you use@propertyand/or@synthesizeto implement the property.