Я настроил сохранение своего свойства. Должен ли я разблокировать его, даже если для него установлено автоматическое освобождение? - PullRequest
0 голосов
/ 24 января 2012

Допустим, у нас есть некоторый код, который выглядит следующим образом:

@interface SomeClass : NSObject
@property (nonatomic, retain) NSString *someString;
@end

@implementation SomeClass
@synthesize someString;
-(id)init {
    if (self=[super init]) {
        someString = [NSString stringWithString:@"some string"];
    }
    return self;
}
@end

Должен ли я освобождать свойство someString в методе dealloc SomeClass, даже если было установлено someStringк автоматическому выпуску, и я никогда не сохранял его в моем методе init?Если это так, я бы просто добавил [someString release] перед [super dealloc] в методе -release.Правильно?

Теперь реальная проблема, с которой я столкнулся, заключается в том, что при использовании Cocos2D я столкнулся с противоречивой ситуацией.Мой код выглядит следующим образом:

@interface SomeLayer : CCLayer
@property (nonatomic, retain) CCSprite *someSprite;
@end

@implementation SomeLayer
@synthesize someSprite;
-(id)init {
    if (self=[super init]) {
        someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];
        [self addChild:someSprite];
    }
    return self;
}
@end

Теперь я добавил someSprite в качестве дочернего элемента к своему слою SomeLayer.Итак, что я должен сделать, чтобы убедиться, что у меня нет утечек памяти здесь?Я мог бы подумать о следующем:

  1. Очевидно, я бы подумал о вызове [someSprite release] в SomeLayer -dealloc методе.но это дает мне EXC_BAD_ACCESS в [super dealloc] (следующая строка).Скорее всего, потому что я не удалил дочерний элемент, а суперкласс пытается получить доступ к только что освобожденному дочернему элементу.
  2. Я вызываю [self removeChild:someSprite cleanup:YES] в методе -dealloc, который удаляет дочерний элемент и также освобождаетЭто.Поэтому мне не нужно следить за [someSprite release].Но эй, метод -dealloc суперкласса CCNode уже делает все это для меня.
  3. Я ничего не делаю.Я бы не стал переопределять метод -dealloc.Что ж, похоже, это работает нормально, но это противоречит утверждению: «если вы сохраняете что-то, вы должны его освободить».

Любая помощь в том, почему я должен освободить объект в случае, если яи почему бы и нет в случае, если II на ранней стадии поможет сэкономить много проблем, связанных с памятью, в долгосрочной перспективе.

Спасибо

Ответы [ 4 ]

3 голосов
/ 24 января 2012
someString = [NSString stringWithString:@"some string"];

Это неправильно. Вы держите указатель на автоматически выпущенный объект, который скоро исчезнет, ​​и когда вы попытаетесь использовать указатель someString, произойдут плохие вещи. Вам следует использовать метод доступа ([self setSomeString:…]), сохранить автоматически выпущенное значение (someString = [… retain]) или использовать метод, который возвращает оставшееся значение (someString = [[NSString alloc] init…]).

В вашем реальном случае вы должны сделать то же самое со спрайтом, вы получаете EXC_BAD_ACCESS, потому что вы перепроизводите спрайт: вы вызываете release, не сохраняя значение. Прочтите Руководство по управлению памятью какао , в долгосрочной перспективе вы избавите себя от многих проблем.

Кстати, я думаю, что ваша главная проблема в том, что вы думаете, что простое присвоение переменной someString сохраняет присвоенное значение. Это не так (не без ARC, если быть более точным). Присвоение переменной экземпляра - это просто, простое присваивание. Если вы хотите пройти через средства доступа, вы должны отправить сообщение ([self setSomeString:…]) или использовать точечную запись (self.someString = …).

1 голос
/ 24 января 2012

Вам действительно нужно прочитать Память Руководство по программированию управления .


Есть два из четырех правил

  • Вы можете стать владельцем объекта, используя команду retain.
  • Когда он вам больше не нужен, вы должны отказаться от права собственности на принадлежащий вам объект

Когда вы объявляете свойство как retain, вам следует вызвать release для соответствующей переменной. В твоем случае твоя сделка должна выглядеть

- (void)dealloc
    [someSprite release];
    [super dealloc];
}

И посмотрите на этот код

 if (self=[super init]) {
        someSprite = [CCSprite spriteWithFile:@"SomeFile.png"]; // here you assign pointer to new object
        [self addChild:someSprite]; // all right, you can use newly created object in this scope
    }
 // but here that object can be deleted from memory and someSprite can points to nothing

Чтобы избежать этого, вам нужно сохранить только что созданный спрайт

someSprite = [[CCSprite spriteWithFile:@"SomeFile.png"] retain];
1 голос
/ 24 января 2012

Вам нужно только освободить объекты, которые вы явно выделяете. Ни один из приведенных вами примеров не был выделен, поэтому они автоматически выпущены. Если вы хотите сохранить автоматически выпущенный объект в течение длительного периода времени, вам нужно сохранить его, и только тогда вам потребуется освободить объект.

Кроме того, если у вас есть свойства, вы должны установить их в nil в viewDidUnload

self.someString = nil;

0 голосов
/ 24 января 2012
@synthesize someSprite;

эта строка переводит количество сохраняемых SomeSprite в 1 .. в тех случаях, когда вы освобождаете его, таким образом, сохраняется до 0 .. освобождение объекта.

[CCSprite spriteWithFile:@"SomeFile.png"];

это объект автоматического выпуска.

когда вы делаете

someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];

, вы указываете someSprite на объект автоматического высвобождения .. поэтому оба теперь равны ..

эта строка теряет всю точку синтеза (сохранить) .. так что теперь измените эту строку на

[self setsomeSprite] =[CCSprite spriteWithFile:@"SomeFile.png"];

, теперь вы просто продолжаете в том же духе, что и есть someSprite release в выпусках ... и все снова будет хорошо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...