#objective-c #memory-management #properties #static-analysis
#objective-c #управление памятью #свойства #статический анализ
Вопрос:
Когда я компилирую с анализатором, я получаю пару сообщений. У меня объявлены эти свойства:
@property (nonatomic, retain) SyncServicePrimary *syncAndCartOne;
@property (nonatomic, retain) SyncServiceSecondary *syncAndCartTwo;
Этот метод вызывается из applicationDidBecomeActive
, и я получаю «Потенциальную утечку выделенного объекта».
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
self.syncAndCartOne = [[SyncServicePrimary alloc] init];
self.syncAndCartTwo = [[SyncServiceSecondary alloc] init];
}
Это вызывается applicationWillResignActive
; здесь я получаю «Неправильное уменьшение количества ссылок объекта».
-(void) removeTheCartObjects{
[self.syncAndCartOne release];
self.syncAndCartOne = Nil;
[self.syncAndCartTwo release];
self.syncAndCartTwo = Nil;
}
Если я установлю для объектов значение autorelease
, ошибка исчезнет, но я хочу, чтобы объекты освобождались, когда приложение скрывается.
Это то, что я делаю правильно, но это слишком далеко, чтобы анализатор мог видеть начало и конец, или это то, что я могу сделать лучше / правильно, чтобы он не жаловался?
Более чем вероятно, что мне не хватает простой концепции в отношении release
alloc
циклов и (я пришел из PHP и C #).
Комментарии:
1. Обратите внимание, что
Nil
это нулевой литерал для указателей на классы. Вместо указателей на объекты следует использоватьnil
.2. Просто чтобы довести это до конца, если я выполняю нулевую проверку экземпляра класса; использование » == Nil» — это не то же самое, что «== nil»?
Ответ №1:
Ваша проблема здесь:
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
self.syncAndCartOne = [[SyncServicePrimary alloc] init];
self.syncAndCartTwo = [[SyncServiceSecondary alloc] init];
}
Вы создаете объекты, а затем сохраняете их (из-за объявления свойства), поэтому у них количество ссылок равно 2, когда на них ссылается только один объект.
Вы должны сделать это следующим образом:
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
SyncServicePrimary *primary = [[SyncServicePrimary alloc] init];
self.syncAndCartOne = primary;
[primary release];
SyncServiceSecondary *secondary = [[SyncServiceSecondary alloc] init];
self.syncAndCartTwo = secondary;
[secondary release];
}
Комментарии:
1. Автоматическое освобождение всего кажется мне ленивой практикой. Конечно, иногда это необходимо, но всегда лучше управлять своей памятью напрямую.
2. И это всегда лучше, потому что …?
3. Я бы хотел избежать автоматического освобождения, особенно с этими объектами, потому что они порождают несколько потоков на основе таймеров и nsnotifications, если я неявно не очищаю их, я не могу быть на 100% уверен, что не будет двух потоков, обращающихся к одной и той же службе rest
4. Итак, просто отметим, что в случае автоматически выпущенных методов класса и сохраненных свойств я могу просто оставить их как есть? например
[self setTitleString:[NSString stringWithFormat:@"%@", mystring]];
5. @misterkoz Вы можете оставить их как есть.
Ответ №2:
Вы определили свойства с помощью атрибута retain
, поэтому анализатор предполагает, что метод установки для свойства выглядит следующим образом:
- (void)setSyncAndCartOne:(SyncServicePrimary *)newValue
{
[newValue retain];
[self->_syncAndCartOne release]; // access the instance variable holding the property value
self->_syncAndCartOne = newValue;
}
Если вы используете @synthesize
, метод setter будет выглядеть так.
Итак, при makeTheCartObjectsForCountry:
возврате объект в syncAndCartOne
имеет счетчик сохранения 2, но должен иметь только счетчик сохранения 1. Вот почему using autorelease
исправляет это.
Вы не должны делать [self.syncAndCartOne release]
по той же причине. Метод setter отправит старый объект a release
при присвоении nil
свойства.
Комментарии:
1. Потрясающе, так что, похоже, я дважды сохраняю и создаю избыточную строку с помощью вызова = nil . хотелось бы, чтобы я мог установить два в качестве принятого ответа…