A simple problem in objective c, about memory leak
Assume I have a interface like:
@interface it:NSObject
{
NSString* string;
}
@end
@implement it
-(id)init
{
if(self = [super init]){
self.string = [[NSString alloc]init];
}
}
-(void)dealloc
{
[self.string release];
[super release];
}
@end
If I use this class in another file and I call this:
it ait = [[it allow] init];
NSString* ano开发者_运维百科therString = [[NSString alloc] init];
ait.string = anotherString;
[anotherString release];
Will this cause the string alloced in init method of it a memory leak? Since the string is not referenced and not autoreleased. If I don't alloc a string in the init method, what will happen when I call ait.string right before assign anotherString to it?
I think you need
@property (nonatomic, retain) NSString *string;
in your interface and
@synthesize string;
in your implementation for self.string to work.
Then, when you do
self.string = [[NSString alloc] init];
in your init method the string will actually have a retain count of 2 because [[NSString alloc] init]
will return a string with a retain count of 1, and using self.string =
will retain the object again because the property is declared as 'retain'. This will result in a memory leak, but you can fix by having:
-(id)init
{
if(self = [super init]){
self.string = @"initString";
}
}
or similar.
Then, onto the actual question, if you do as above the string allocated in init wont leak when you reassign with self.string =
because properties marked as 'retain' release their current object before retaining the new one.
If you don't assign a string to self.string
in the init method it doesn't matter because self.string
will just return nil
, which you can then deal with in your program.
Will this cause the string alloced in init method of it a memory leak? Since the string is not referenced and not autoreleased.
Yes, exactly. You seem to have got it.
If I don't alloc a string in the init method, what will happen when I call ait.string right before assign anotherString to it?
Do you mean in the following case you are unsure what unknownObject would refer to?:-
It *ait = [[It allow] init];
NSString *unknownObject = ait.string;
This is nonsense. Did you forget to add the accessor methods?
Objective-c doesn't use 'dot syntax' to access instance variables, like, say, Java. If you have an instance of your class 'it' you can only access the 'string' variable from outside that instance by calling the accessor 'getter' method. This is not optional self.string is just a shortcut for the method call [self string] and this method doesn't exist in the code you showed.
Assuming the accessor method are defined elsewhere, the instance variable you called string (this is the worlds worst variable name) is equal to nil. In Objective-c you have to treat nil objects very carefully as the behaviour is different from how many other languages treat the similar null.
In Objective-c this is fine:
NSString *nilString = nil;
[nilString writeToFile:@"/this_file_cannot_exist.data"];
Many other languages would crash here or throw an exception; This can be dangerous, as an operation may fail but your app will continue running. It can also be great tho, because in other languages you will see lots of this..
someObject = controller.currentValue()
if( someObject!=null )
someObject.writeToFile("myFile.data")
In Objective-c the 'if(..)' line isn't needed at all.
You must be careful not to call the accessor method inside your init and dealloc methods, as this can break subclasses. Instead of
- (void)dealloc {
[self.string release]; // This is [[self string] release]
...
you should just use
- (void)dealloc {
[string release];
...
As well as being dangerous the call to [self string] is unnecessary. The same is true in your init methods
if(self=[super init]){
self.string = [[NSString alloc]init]; // shortcut for [self setString:[[NSString alloc] init]]
...
just use
if(self=[super init]){
string = [[NSString alloc] init];
...
You're missing the @property in order to use self.string.
Add this to your .h file
@property (readwrite, copy) NSString *string;
Using Copy instead of Retain will prevent the string from memory-leak even if you release anotherString.
@interface it:NSObject
{
NSString* string;
}
//you should declare a property in order to call it with 'self' prefix
@property (nonatomic, retain) NSString* string;
@end
@implementation it
//you should synthesize your property
@synthesize string;
-(id)init
{
if(self = [super init]){
//you don't to initialize NSString right here (memory leak will have place)
//self.string = [[NSString alloc]init];
//you can store a default value like this (can be omitted):
self.string = @"Default value";
}
return self;
}
-(void)dealloc
{
[self.string release];
[super release];
}
@end
And everything regarding memory management in this class will be fine.
精彩评论