Когда выпустить UIImage?

Я использую следующий код для рисования фрагмента изображения

UIImage* subIm = getSubImage( large, rect );
[subIm drawInRect:self.bounds];

где getSubImage определяется следующим образом

    UIImage* getSubImage(UIImage* uim, CGRect rc){
      CGImageRef imref  = CGImageCreateWithImageInRect(uim.CGImage, rc); 
      UIImage*   sub = [UIImage imageWithCGImage:imref];
      CGImageRelease(imref);
        NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
      return sub;
   }//getSubImage

Код правильный?

Безопасно ли использовать imref для "CGImageRelease"?

Имеет ли sub "CGImageRetained" imref?

Следует ли мне выпустить subIm (если я это сделаю, я получу сообщение об ошибке)?

Содержится ли subIm в пуле autorelease, и если да, то как мне это узнать?

В общем, можно ли проверить, содержится ли объект в пуле автозапуска (для целей отладки)?


person ragnarius    schedule 28.12.2010    source источник
comment
не звоните retainCount. Возвращенное число обычно бессмысленно.   -  person bbum    schedule 28.12.2010


Ответы (4)


SubIm зарегистрирован в пуле AutoRelease, потому что этот объект фактически создается методом класса imageWithCGImage, и что правило состоит в том, что экземпляры, созданные методами класса, всегда должны возвращать автоматически выпущенные экземпляры.

Код правильный, хотя я не понимаю, почему вы используете синтаксис C вместо синтаксиса Obj-C для определения вашей функции

person VdesmedT    schedule 28.12.2010
comment
Спасибо за это правило, поможет! Мне все еще интересно, есть ли у sub CGImageRetained imref ... В документации только сказано, что imref не кешируется ... - person ragnarius; 28.12.2010
comment
Я думаю, он сохранил это, и вы должны освободить его. Понятия не имею, почему после CGImageRelease значение параметра keepCount все еще равно 1, и возможно, что CGImageRelease добавлен в пул выпуска .. Я не знаю! Проверить до и после релиза может быть? - person VdesmedT; 28.12.2010
comment
Ну, это keepCount под-изображения, и он должен быть 1, если он находится в пуле AutoRelease. Я не знаю, как проверить keepCount для imref, потому что это не объект objective-c. - person ragnarius; 28.12.2010
comment
CGImageCreateWithImageInRect создает объект, и вы несете ответственность за его освобождение. Если вы затем создадите из него автоматически выпущенный uiimage, вы можете (и должны) освободить cgimageref (как и вы). - person drunknbass; 29.12.2010
comment
В конечном итоге не имеет значения, каков счетчик сохранения вашего CGImageRef - вы его создали, поэтому вы должны его выпустить. Если UIImage хочет сохранить его, то UIImage обязан сделать это, сохранив или скопировав его, а не ваш. Например, UIImage может скопировать элемент, что означает, что ваш экземпляр будет протекать, а вы не выпускаете его. - person Jim Dovey; 29.12.2010
comment
@drunknbass и @Jim, спасибо, теперь я начинаю это понимать. - person ragnarius; 29.12.2010

Не звонить -retainCount

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

Сохраненные подсчеты следует рассматривать только как дельты; если вы увеличиваете счетчик удержания, вы должны уменьшить его.

Данный:

UIImage* getSubImage(UIImage* uim, CGRect rc){
  CGImageRef imref  = CGImageCreateWithImageInRect(uim.CGImage, rc); 
  UIImage*   sub = [UIImage imageWithCGImage:imref];
  CGImageRelease(imref);
    NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
  return sub;
}//getSubImage

imageWithCGImage: возвращает автоматически выпущенный объект. Счетчик сохранения не имеет значения, поскольку imageWithCGImage: может внутренне выполнять любое количество вещей - кэширование и т. Д. - которые могут повлиять на счетчик удержания.

get* - странный шаблон для использования в программировании какао. Вы просто не так много видите.

Я бы предложил что-то вроде:

- (UIImage *) subImage: (UIImage *) anImage inRect: (CGRect) aRect
{
      CGImageRef imageRef  = CGImageCreateWithImageInRect(anImage.CGImage, aRect); 
      UIImage*   subImage = [UIImage imageWithCGImage: imageRef];
      CGImageRelease(imageRef);
      return subImage;
}
person bbum    schedule 28.12.2010
comment
@ragnarius get обычно используется, когда за это отвечает вызывающая функция (освобождение и т. д.), поэтому в этом контексте это кажется неправильным и на первый взгляд может сбить с толку любого, кто поддерживает этот код. - person drunknbass; 28.12.2010
comment
@drunknbass get - это наоборот - он возвращает то, что принадлежит получателю, а не вызывающему. new или копировать или выделять возвращаемые элементы, которые неявно сохраняются от имени вызывающего. Посмотрите примеры API CoreFoundation; CFURLCopyPath () возвращает новый CFStringRef, который вызывающий должен освободить, но CFArrayGetValueAtIndex () просто возвращает элемент, который не нуждается в управлении вызывающим. - person Jim Dovey; 29.12.2010
comment
согласно c.crap.ps/3n6N вы должны использовать префикс get для функций, которые передают переменные, которые могут быть видоизмененным / модифицированным. Я на самом деле видел, как многие люди использовали его по-разному, но большинство из них в конечном итоге получали объект, который не выпускается автоматически. - person drunknbass; 29.12.2010

Существует соглашение об именах для управления памятью. Все коды какао подчиняются этому правилу:

Основные правила управления памятью

Я настоятельно рекомендую вам прочитать этот документ и тоже следовать правилу. Правило именования также является частью Какао.

Из справочной документации:

Вам принадлежит любой созданный вами объект. Вы «создаете» объект, используя метод, имя которого начинается с «alloc» или «new» или содержит «копию» (например, alloc, newObject или mutableCopy).

Вы должны отказаться от владения принадлежащими вам объектами, когда закончите с ними. Вы отказываетесь от владения объектом, отправляя ему сообщение о выпуске или сообщение об автоматическом выпуске (автоматическое выпуск более подробно обсуждается в разделе «Автоспуск»). Поэтому в терминологии Какао отказ от владения объектом обычно называется «освобождением» объекта.

Аналогичное правило действует для функций языка C в Core Foundation framework. Однако таких автозапусков нет. Вы должны прояснить все в своей документации, если хотите создать объект Objective-C с функциями C.

И это может быть вам полезно: imageWithCGImage и память

person eonil    schedule 28.12.2010
comment
+1 Хорошо, я владею объектом imref и поэтому вызываю CGImageRelease. Я не владею подобъектом и поэтому не вызываю релиз и могу сделать вывод, что он уже находится в autoReleasePool. - person ragnarius; 28.12.2010
comment
@ragnarius точно. :) Как только вы усвоите эти простые правила владения, управление памятью станет намного проще. - person Dave DeLong; 28.12.2010

  CGImageRelease(imref);
    NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
  return sub;

Поскольку в вашем методе нет ключевого слова alloc, keep, copy ..., вы должны автоматически освободить UIImage перед его возвратом. Но фабричный метод UIImage уже сделал это за вас. Помните, что даже если вы автоматически разблокируете сабвуфер, счетчик удержания по-прежнему равен 1.

person vodkhang    schedule 28.12.2010
comment
Метод, отправляющий сообщение alloc, должен освободить или автоматически освободить объект. В случае фабричного метода это метод, отправивший alloc, так что это метод, который отправляет autorelease. Тем не менее, не беспокойтесь о реализациях других классов - ваши собственные обязанности четко определены, и все, что вам нужно сделать, это следовать им. - person Peter Hosey; 28.12.2010