Цель C - является ли init плохим местом для реализации фабрики?
Я реализовал старый шаблон init-as-a-factory, но в одном конкретном случае (но не в других!) Анализатор получает предупреждение об утечках памяти. И действительно, глядя на правила политики управления памятью какао, это alloc
не init
, который может вернуть +1-retain-count объектов.
Так что получается, что:
- Высвобождение
self
и возвращая новый объект изinit
строго говоря, против правил. - Многие места в Интернете продвигают эту технику, и из-за тандемной природы alloc/init это работает.
- Анализатор иногда жалуется на это, а иногда нет.
Так... мы все время делали это неправильно?
3 ответа
Вы можете реализовать init
как этот, который должен выпустить self
чтобы сбалансировать удерживать счет от alloc
вызов.
- (id)initWithSomething:(id)something
{
[self release]; // don't need this line for ARC
self = nil;
return [[PrivateSubClass alloc] initWithSomething:something];
}
и это если очень часто реализовать init
как заводской метод. например NSArray
, NSDictionary
, NSString
Как сказал Гейдж, будет гораздо понятнее, если вы разместите фрагмент кода, а не объяснения.
В любом случае, вы можете переместить свою фабрику в метод класса, так что у вас не будет такой проблемы вообще. Я имею в виду что-то вроде этого:
MyClass* instance = [MyClass instanceWithParameters:params];
@interface MyClass
+ (MyClass*) instanceWithParameters:(ParamType)params;
@end
Трудно сказать, не зная, что за код вызывает поведение анализатора, но, как правило, вот пара удобных для компилятора способов определения методов init/factory.
Классический alloc/init
- (instancetype)initWithParameter:(id)parameter {
if(self = [super init]) {
_parameter = parameter;
}
return self;
}
использование
MyCustomClass * myInstance = [[MyCustomClass alloc] initWithParameter:foo];
Это создаст экземпляр со счетом удержания +1. Под ARC это будет автоматически управляться должным образом, поскольку оно следует правилу NARC (New, Alloc, Retain, Copy). По той же причине в средах до ARC он должен быть явно освобожден клиентом.
Пользовательский метод фабрики
ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[self alloc] initWithParameter:parameter]; // assuming -initWithParameter: defined
}
Pre-ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[[self alloc] initWithParameter:parameter] autorelease]; // assuming -initWithParameter: defined
}
использование
MyCustomClass * myInstance = [MyCustomClass canIHazInstanceWithParameter:foo];
Как в ARC, так и в pre-ARC метод возвращает автоматически выпущенный экземпляр (это явно более очевидно в реализации до ARC), который не должен управляться клиентом.
замечания
Вы могли заметить
instancetype
ключевое слово. Это удобное расширение языка, представленное Clang, которое превращает компилятор в дорогого друга при реализации ваших собственных методов конструкторов / фабрики. Я написал статью на эту тему, которая может иметь отношение к вам.Являются ли фабричные методы предпочтительнее
init
методы спорны. С точки зрения клиента это не имеет большого значения в ARC, при условии, что вы тщательно соблюдаете соглашения об именах, хотя я лично склонен показывать фабричные методы в интерфейсе при реализации пользовательскихinit
методы только внутри (как я делал в примерах выше). Это больше вопрос стиля, чем практическая забота.