Как вам удается освободить объект, созданный в методе экземпляра на iPhone, без автоматического выпуска? - PullRequest
4 голосов
/ 11 февраля 2010

Я довольно новичок в разработке для iPhone и столкнулся с препятствиями в своем понимании управления памятью. Я прочитал Руководство по управлению памятью для какао и прочитал много, много вопросов и ответов по SO, но не нашел полного ответа.

Если у меня есть метод экземпляра, который создает объект, кажется, что каждый пример, который я видел, использует вызов autorelease:

-(NSArray *)findThings {
    NSArray* things = [[[NSArray alloc] init] autorelease];
    // add some lovely things to my shiny new array
    return things;
}

Забыв о надуманном примере, все, что я читал о передовых практиках разработки для iPhone, говорит о том, что пулы с автоматическим выпуском не рекомендуется, но как я могу реализовать приведенный выше пример без него? Если этот метод вызывается много-много раз, возникает ощущение, что я рискую засорить пул авто-релизов iPhone, ну, в общем, «вещами», что, кажется, идет вразрез с необходимостью свести к минимуму использование ресурсов на такой ограниченной платформе. .

Я считал следующее:

-(NSArray *)findThings {
    NSArray* things = [[NSArray alloc] init];
    // add some lovely things to my shiny new array
    [things release];
    return things;
}

Но тогда «вещи» будут иметь нулевой счет до того, как они перейдут к вызывающему методу, поэтому я чувствую, что существует значительный риск того, что объект будет удален между вызовом [вещей выпуска] и методом, который вызывает findThings фактически используя результат.

Меня немного смутило правило из Руководства по управлению памятью, которое гласит:

Полученный объект обычно гарантированно оставаться в силе в течение метод был получен в. (...) Этот метод может также безопасно вернуть объект его призыватель.

Я не был уверен, что это означало, что как создатель метода экземпляра я мог безопасно выполнить освобождение без риска освобождения объекта до тех пор, пока не закончится область действия вызывающего метода, или как пользователь классов в предоставленных инфраструктурах Я могу предположить, что мне не нужно было беспокоиться о сохранении / выпуске / etc для объектов, которые я получил от этих классов, если у метода не было нового / init / alloc / copy / что-либо в его имени.

Итак, подведем итог,

  • Можно ли использовать release перед возвратом объекта вместо автоматического выпуска, чтобы избежать использования пула автоматического выпуска на iPhone?
  • Если нет, есть ли лучший шаблон для этого, который не включает пул авто-релиза?
  • Я что-то упустил здесь? Кажется, в документах есть дыра.

Заранее спасибо

Ответы [ 6 ]

9 голосов
/ 11 февраля 2010

Забыв о надуманном примере, все, что я читал о передовых практиках разработки для iPhone, говорит о том, что пулы автоматического выпуска не рекомендуется

Автозапуск бассейнов не рекомендуется; они используются везде в Какао, и при правильном использовании они ноль влияют на использование памяти. Пулы авто-выпуска вызывают беспокойство только тогда, когда они искусственно продлевают срок службы большого количества объектов, скажем, в цикле, и в этом случае вы будете управлять своими пулами автоматического выпуска вручную.

4 голосов
/ 11 февраля 2010

Да, вы правы, пулы авто-релиза не рекомендуются для разработки на iPhone, когда они не являются абсолютно необходимыми. Они не одобряются, потому что это позволяет объектам оставаться в памяти дольше, чем это необходимо, это проблема при разработке приложений для iPhone, где не хватает памяти. Автоматически освобожденные объекты не освобождаются до тех пор, пока они не вернутся в основной пул автоматического выпуска, созданный в main.c, и это может занять много времени. (если вы не создали свой собственный пул автоматического выпуска, я расскажу об этом последним.)

Случай, когда объект автоматического освобождения не требуется:

NSString *string = [NSString stringWithString:@"hello world"];
//use string

Первый случай более удобен , поскольку мне не нужно беспокоиться о выпуске string позже, но его можно было легко заменить на:

NSString *string = [[NSString alloc] initWithString:@"hello world"];
// use string
[string release];

В этих случаях рекомендуется избегать автоматического освобождения объекта.


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

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

-(NSArray *)findThings {
    NSArray* things = [[[NSArray alloc] init] autorelease];
    // add some lovely things to my shiny new array
    return things;
}

Поскольку объект недействителен, как только вы позвоните release.

-(NSArray *)findThings {
    NSArray* things = [[NSArray alloc] init];
    // add some lovely things to my shiny new array
    [things release];
    // things is now in invalid object if you could potentially use things later it should be set to nil to avoid a crash
    things = nil; // sending messages to nil is okay, it won't cause a crash, sending messages to a released object is not okay, it can cause unpredictable crashes.        
    return things;
}

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

-(void)useLotsOfAutoReleasedObjects {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    // lots of autoreleased object
    // large autoreleased objects
    [pool drain];  // autorelease objects are released too
}

[пул стока] также освобождает пул, для получения дополнительной информации см. NSAutoreleasePool Reference .

3 голосов
/ 11 февраля 2010

Хорошо autorelease предназначен для того, чтобы охватить точные сценарии, с которыми у вас возникли проблемы.

1 голос
/ 11 февраля 2010

Вы следуете правилу Create .

0 голосов
/ 11 февраля 2010

Как и все остальные, эта проблема - то, для чего был разработан авто-релиз.

При создании и возврате объектов из метода экземпляра объект должен автоматически освобождаться перед его возвращением.

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

Когда отправителю возвращается объект из метода, который не содержит слов Create, Alloc, Retain или New, ожидается, что результат будет автоматически освобожден согласно соглашению. Это позволяет программисту легко узнать, что объект должен быть сохранен, если он хочет сохранить его, или что его можно безопасно использовать и забыть в текущей области, не беспокоясь о его памяти.

0 голосов
/ 11 февраля 2010

избавь себя от хлопот .. просто сделай:

- (NSArray *)findThings{
      NSArray *things = [NSArray array];
      return things;
}

Как уже упоминалось ранее, stefanB, autorelease здесь, чтобы решить проблему, с которой вы столкнулись. другое решение может состоять в том, что вы просто сохраните его и освободите его там, где вы его используете ... но это может привести к утечке, если вы не будете осторожны.

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