#objective-c #xcode #cocoa-touch #analyzer
#objective-c #xcode #cocoa-touch #анализатор
Вопрос:
Я получаю утечку анализатора, однако это тот же код, который я использую в другом месте без проблем. Я знаю, что использую alloc, и поэтому я должен освободить, но я делаю это в dealloc.
Что я делаю не так?
Заголовочный файл:
@interface myViewController : UIViewController <UITableViewDataSource,
UITableViewDelegate> {
UIBarButtonItem *addButton;
}
@property (nonatomic, retain) UIBarButtonItem *addButton;
Основной файл:
@synthesize addButton;
- (void)viewDidLoad {
NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:3];
addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(btnNavAddPressed:)];
addButton.style = UIBarButtonItemStyleBordered;
[buttons addObject:addButton];
[tools setItems:buttons animated:NO];
[buttons release];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithCustomView:tools];
addButton.enabled = FALSE;
- (void)dealloc {
[addButton release];
Ответ №1:
когда вы используете свойство и присваиваете ему указанные вами атрибуты, определите, увеличивается ли retainCount, если вы присваиваете свойство. В вашем случае вы указали « retain
«, что означает, что функция setter, которая обрабатывает присвоение вашему свойству, автоматически увеличит количество сохранений для объекта.
Однако, когда вы пишете
addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(btnNavAddPressed:)];
вы создаете opject с уже сохраненным количеством == 1, поэтому при назначении у него будет сохраненное количество 2. правильный способ сделать это — создать временную переменную и создать объект, затем присвоить временную переменную свойству, после чего отпустить temp. переменная:
UIBarButtonItem* tmp = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(btnNavAddPressed:)];
self.addButton = tmp;
[tmp release];
конечно, я бы рекомендовал в качестве имени переменной более описательное имя, чем ‘temp’.
Комментарии:
1. это вводящий в заблуждение совет. Код операционной системы wrt
addButton
в порядке как есть. Он правильно сохраняет выделенный объект непосредственно в iVar и освобождает его вdealloc
.
Ответ №2:
Вы не используете установщик, код должен быть:
self.addButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(btnNavAddPressed:)] autorelease];
Такого рода проблем можно избежать, используя ivar, имя которого отличается от имени свойства. Это выполняется в @synthesize
инструкции:
@synthesize addButton = _addButton;
Таким образом, любое упущение self
приведет к сообщению об ошибке.
Вот полная реализация (за исключением того, что tools
не определено), свойство addButton обрабатывается во всех местах:
@interface myViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
}
@property (nonatomic, retain) UIBarButtonItem *addButton;
@end
@implementation myViewController
@synthesize addButton = _addButton;
- (void)viewDidLoad {
NSMutableArray* buttons = [NSMutableArray array];
self.addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(btnNavAddPressed:)];
self.addButton.style = UIBarButtonItemStyleBordered;
[buttons addObject:self.addButton];
[tools setItems:buttons animated:NO];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:tools] autorelease];
self.addButton.enabled = FALSE;
}
- (void)dealloc {
[_addButton release];
}
@end
Комментарии:
1. Не приведет ли это к утечке памяти? (эти комментарии стали намного сложнее после ARC!)
2. @jrturton Упс, исправлено в ответе. Спасибо! Конечно, в ARC авторелиз не требуется.
3. Вот что я имею в виду, раньше было действительно легко обнаружить утечки, теперь появился целый дополнительный слой. Я предпочитаю старые добрые времена…
4. Пусть это будут «старые добрые времена». 🙂 Я считаю, что писать под ARC намного проще.
5. @CocoaFu, похоже, это не исправляет проблему и
@synthesize addButton = _ addButton;
выдает мне ошибкуParse Issue: Expected ';' after @synthesize
. Также пробовал использовать self. перед всеми вызовами addButton. Есть дополнительные советы?
Ответ №3:
Оба приведенных выше ответа вводят в заблуждение. Вам не нужно использовать установщик, вполне нормально назначать объекты непосредственно iVars. Однако вам нужно освободить все, что вы выделяете или сохраняете. Проблема, с которой вы столкнулись, заключается вот в чем:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:tools];
Эта строка выделяет UIBarButtonItem
экземпляр и присваивает ему rightBarButtonItem
свойство navigationItem
. Это означает, что navigationItem
сохраняет UIBarButtonItem
и несет ответственность за это сохранение. Вы несете ответственность за его освобождение с помощью alloc
, а вы нет. Измените код на этот:
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:tools] autorelease];
и эта утечка устраняется.
Комментарии:
1. Проблемы такого типа являются одним из наиболее распространенных препятствий для разработчиков iOS. Это действительно становится проще / естественнее по мере того, как вы набираетесь опыта. Если вы используете xcode 4.2, я рекомендую прочитать документы по ARC (автоматический подсчет ссылок) и перенести ваш проект на это. Это не меняет правила управления памятью, но позволяет компилятору выполнять почти всю работу за вас.
Ответ №4:
Вы не используете заявленное свойство, но я не вижу никакой проблемы с addButton
. Утечка, похоже, больше в:
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithCustomView:tools];
Просто добавьте autorelease
, и утечка исчезнет.
Комментарии:
1. Это странно, я скопировал ваш код, и отсутствие автоматического освобождения — единственная проблема, обнаруженная мной и анализатором. Очистить и проанализировать? Или вы можете опубликовать скриншот анализатора (тот, что со стрелками)?