Простая проблема в задаче c об утечке памяти - PullRequest
1 голос
/ 12 марта 2011

Предположим, у меня есть такой интерфейс:

@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

Если я использую этот класс в другом файле и вызываю это:

it ait = [[it allow] init];
NSString* anotherString = [[NSString alloc] init];
ait.string = anotherString;
[anotherString release];

Будет ли это вызывать строку, выделенную в методе initэто утечка памяти?Поскольку на строку не ссылаются и не выпускаются автоматически.Если я не выделю строку в методе init, что произойдет, когда я вызову ait.string прямо перед тем, как присвоить ему другую String?

Ответы [ 4 ]

1 голос
/ 12 марта 2011

Я думаю, вам нужно

@property (nonatomic, retain) NSString *string;

в вашем интерфейсе и

@synthesize string;

в вашей реализации для self.string для работы.

Затем, когда вы делаете

self.string = [[NSString alloc] init];

в вашем методе init строка на самом деле будет иметь счетчик хранения 2, потому что [[NSString alloc] init] вернет строку с счетом хранения 1, а использование self.string = снова сохранит объект, потому чтособственность объявляется как «сохранить».Это приведет к утечке памяти, но вы можете исправить, набрав:

-(id)init
{
  if(self = [super init]){
    self.string = @"initString";
  }
}

или аналогичный.

Затем перейдите к актуальному вопросу, если вы сделаете, как указано выше, строку, выделенную в initне будет течь при переназначении с помощью self.string =, потому что свойства, помеченные как 'retain', освобождают свой текущий объект перед сохранением нового.

Если вы не назначите строку для self.string в методе init, он неЭто не имеет значения, потому что self.string просто вернет nil, с чем вы можете иметь дело в вашей программе.

0 голосов
/ 12 марта 2011

Вам не хватает @property для использования self.string.

Добавьте это в ваш .h файл

@property (readwrite, copy) NSString *string;

Использование Copy вместо Retain предотвратит строку изутечка памяти, даже если вы освобождаете anotherString.

0 голосов
/ 12 марта 2011

Будет ли это причиной строки, выделенной в метод init это утечка памяти? поскольку на строку не ссылаются и не autoreleased.

Да, именно так. Вы, кажется, получили это.

Если я не выделю строку в init метод, что будет, когда я позвоню ait.string прямо перед назначением еще одна строка?

Вы имеете в виду, что в следующем случае вы не уверены, на что ссылается unknownObject?: -

It *ait = [[It allow] init];
NSString *unknownObject = ait.string;

Это чепуха. Вы забыли добавить методы доступа?

Objective-c не использует точечный синтаксис для доступа к переменным экземпляра, как, скажем, Java. Если у вас есть экземпляр вашего класса 'it', вы можете получить доступ к переменной '1013' * string только из этого экземпляра , вызвав метод доступа getter. Это не является обязательным. Self.string является просто ярлыком для вызова метода [self string], и этот метод не существует в показанном вами коде.

При условии, что метод доступа определен в другом месте, переменная экземпляра, которую вы назвали string ( это худшее в мире имя переменной) равна nil . В Objective-c вы должны очень аккуратно обращаться с ноль объектами, поскольку поведение отличается от того, как многие другие языки относятся к аналогичному null .

В Objective-c это нормально:

NSString *nilString = nil;
[nilString writeToFile:@"/this_file_cannot_exist.data"];

Многие другие языки могут потерпеть крах здесь или вызвать исключение; Это может быть опасно, так как операция может завершиться ошибкой, но ваше приложение продолжит работу. Это также может быть здорово, потому что на других языках вы увидите много этого ..

someObject = controller.currentValue()
if( someObject!=null )
  someObject.writeToFile("myFile.data")

В Objective-c строка 'if (..)' вообще не нужна.

Вы должны быть осторожны, чтобы не вызывать метод доступа внутри методов init и dealloc, так как это может нарушить подклассы. Вместо

- (void)dealloc {
   [self.string release]; // This is [[self string] release]
   ...

Вы должны просто использовать

- (void)dealloc {
   [string release];
   ...

Наряду с опасностью, вызов [self string] не нужен. То же самое верно в ваших методах инициализации

if(self=[super init]){
  self.string = [[NSString alloc]init]; // shortcut for [self setString:[[NSString alloc] init]]
  ...

просто используйте

if(self=[super init]){
  string = [[NSString alloc] init];
  ...
0 голосов
/ 12 марта 2011
@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

И все, что касается управления памятью в этом классе, будет в порядке.

...