Методы класса, которые создают новые экземпляры

Помимо стандартного шаблона [[MyClass alloc] init], некоторые объекты создаются из статических методов, таких как MyClass *obj = [MyClass classWithString:@"blabla"].

Согласно широко распространенным руководствам по управлению памятью (включая руководства Apple), вы несете ответственность только за освобождение объектов, которые вы alloc.

Может ли кто-нибудь предоставить мне шаблон для таких методов? Как вы возвращаете выделенный объект (возможно, [self alloc]; return self;)? Как убедиться, что он будет выпущен?


person pistacchio    schedule 13.05.2011    source источник
comment
Не только +alloc — любой метод, имя которого начинается с alloc, new, copy, mutableCopy, а также -retain.   -  person    schedule 13.05.2011


Ответы (4)


Это методы класса, а не статические методы1. Этот конкретный тип, создающий автоматически освобождаемые объекты, может называться «фабричными методами» (ранее также «конструкторами удобства»), и они обсуждаются в Руководство по концепциям ObjC. Они идут примерно так:

+ (instancetype)whatsisWithThingummy: (Thingummy *)theThingummy {
    return [[self alloc] initWithThingummy:theThingummy];
}

Где Whatsis — ваш класс, а Thingummy — другой класс, который использует ваш класс.

Если вы не компилируете с помощью ARC, соглашение состоит в том, чтобы autorelease экземпляр перед его возвратом.

instancetype ключевое слово было введено Clang для таких методов. ; в сочетании с self (который является объектом класса2 в методе класса) он обеспечивает правильное поведение подкласса: метод создает экземпляр класса, который получил сообщение.3 instancetype позволяет компилятору выполнять более строгую проверку типов, чем id.

Иллюстрация этого использования в подклассах из фреймворка: +[NSString stringWithFormat:] возвращает экземпляр NSString, тогда как +[NSMutableString stringWithFormat:] возвращает экземпляр подкласса NSMutableString, при этом NSMutableString не требуется для явного переопределения метода.

Как обсуждалось в документе [Основы][1], эти фабричные методы можно использовать и по-другому, например, для доступа к синглтону или оценки необходимого распределения памяти перед его выполнением (возможно, но менее < em>удобно, со стандартной парой alloc/init).


1"Статические методы" в Java или C++, "методы класса" в Objective-C. В ObjC нет статических методов

2В то время как в экземпляре метод self, по сути, является ссылкой на экземпляр.

3Ранее как и обычные методы инициализации (initWith...), вы бы использовали id в качестве возвращаемого типа. Использование определенного имени класса без необходимости заставляет подклассы переопределять метод.

person jscs    schedule 13.05.2011
comment
+1 за id в качестве возвращаемого типа, +1 за ссылку на документ, +1 за методы класса, +1 за удобные конструкторы. - person ; 13.05.2011
comment
@Bavarious: Спасибо. Я рад, что вы не сняли балл за плохие метасинтаксические переменные. :) - person jscs; 13.05.2011
comment
+1 за упоминание в сноске расширения Clang instancetype. - person Andrew Madsen; 08.01.2013
comment
+1, хотя мне пришлось воздержаться от редактирования ваших метасинтаксических переменных. - person i_am_jorf; 06.03.2013
comment
@Josh: «Ранее, как и в случае с обычными методами инициализации (initWith...), вы бы использовали id в качестве возвращаемого типа». Используется ли id в качестве возвращаемого типа с методами экземпляра стиля -initWith, если он не включен как часть метода класса? - person cheznead; 25.02.2015
comment
@shinnyWhack: instancetpye является неявным для метода init..., поэтому вы можете использовать id или instancetype. - person jscs; 25.02.2015

Объекты, возвращенные фабричными методами, должны быть освобождены автоматически, то есть они будут очищены, когда соответствующий пул автоматического освобождения будет опустошен. Это означает, что вы не являетесь владельцем возвращенных объектов, если вы не copy или retain их. Ниже приведен пример фабричного метода:

+ (id)myClassWithString:(NSString *)string {
    return [[[MyClass alloc] initWithString:string] autorelease];
}
person Community    schedule 13.05.2011
comment
Применяется ли использование autorelease при использовании ARC? - person raffian; 28.06.2012
comment
@SAFX, нет, вы можете проверить эти заметки, сделанные Apple: developer.apple.com/library/mac/#releasenotes/ObjectiveC/ - person marsalal1014; 10.09.2012

Эти методы просто возвращают автоматически выпущенную версию объекта.

+(MyClass*)class
{
  MyClass* object = [[MyClass alloc] init];
  return [object autorelease];
}
person Thomson Comer    schedule 13.05.2011
comment
Из-за наследования фабричные методы обычно имеют тип возвращаемого значения id. - person ; 13.05.2011

Современный способ сделать это с помощью ARC и последнего компилятора:

+ (instancetype) myClassWithString:(NSString *)string {
     return [[MyClass alloc] initWithString:string];
}
  • Нет необходимости в автоматическом выпуске с ARC.
  • instancetype обеспечивает лучшую проверку во время компиляции, делая возможным создание подклассов.
person Robert    schedule 16.07.2013
comment
Не лучше переименовать метод, чтобы он начинался со слова «новый», или использовать макрос атрибута NS_RETURNS_RETAINED? Насколько я понимаю, это сообщает ARC, что он получает объект +1, владельцем которого должен стать вызывающий. Однако это не обязательно, поскольку реализация с автоматическим выпуском по умолчанию приведет к тому же результату. - person karwag; 16.08.2013