Clang добавляет ключевое слово, instancetype
которое, насколько я вижу, заменяет id
тип возврата в -alloc
и init
.
Есть ли польза от использования instancetype
вместо id
?
objective-c
instancetype
griotspeak
источник
источник
id
, были замененыinstancetype
, дажеinit
изNSObject
. Если вы хотите, чтобы ваш код был совместим с Swift, вы должны использоватьinstancetype
Ответы:
Там определенно есть выгода. Когда вы используете 'id', вы вообще не получаете проверку типов. С помощью instancetype компилятор и IDE знают, какой тип объектов возвращается, и могут лучше проверять ваш код и лучше выполнять автозаполнение.
Используйте его только тогда, когда это имеет смысл (т. Е. Метод, который возвращает экземпляр этого класса); Идентификатор все еще полезен.
источник
alloc
,init
И т.д. автоматически повышены доinstancetype
компилятора. Это не значит, что нет никакой пользы; есть, но это не так.Да, есть преимущества использования
instancetype
во всех случаях, когда это применимо. Я объясню более подробно, но позвольте мне начать с этого жирного выражения: используйте,instancetype
когда это уместно, то есть всякий раз, когда класс возвращает экземпляр того же класса.Фактически, вот что Apple сейчас говорит по этому вопросу:
После этого давайте продолжим и объясним, почему это хорошая идея.
Сначала несколько определений:
Для фабрики классов вы всегда должны использовать
instancetype
. Компилятор не конвертируется автоматическиid
вinstancetype
. Этоid
общий объект. Но если вы сделаете это,instancetype
компилятор знает, какой тип объекта возвращает метод.Это не академическая проблема. Например,
[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
сгенерирует ошибку в Mac OS X ( только ). Несколько методов с именем 'writeData:' найдены с несоответствующим результатом, типом параметра или атрибутами . Причина в том, что и NSFileHandle, и NSURLHandle предоставляютwriteData:
. Так как[NSFileHandle fileHandleWithStandardOutput]
возвращает anid
, компилятор не уверен, какой классwriteData:
вызывается.Вам нужно обойти это, используя либо:
или:
Конечно, лучшим решением будет объявить
fileHandleWithStandardOutput
возвращениеinstancetype
. Тогда приведение или назначение не является необходимым.(Обратите внимание, что в iOS этот пример не выдаст ошибку, поскольку только
NSFileHandle
предоставляетwriteData:
там. Существуют и другие примеры, такие какlength
, который возвращает aCGFloat
из,UILayoutSupport
но aNSUInteger
изNSString
.)Примечание : так как я написал это, заголовки macOS были изменены, чтобы возвращать
NSFileHandle
вместо вместоid
.Для инициализаторов это сложнее. Когда вы печатаете это:
... компилятор сделает вид, что вы набрали это:
Это было необходимо для ARC. Это описано в типах результатов Clang Language Extensions . Вот почему люди скажут вам, что нет необходимости использовать
instancetype
, хотя я утверждаю, что вы должны. Остальная часть этого ответа имеет дело с этим.Есть три преимущества:
Явный
Это правда, что нет никакой технической выгоды для возвращения
instancetype
изinit
. Но это потому, что компилятор автоматически преобразуетid
вinstancetype
. Вы полагаетесь на эту причуду; в то время как вы пишете, чтоinit
возвращает anid
, компилятор интерпретирует его так, как будто он возвращаетinstancetype
.Это эквивалентно компилятору:
Это не эквивалентно вашим глазам. В лучшем случае вы научитесь игнорировать разницу и просматривать ее. Это не то, что вы должны научиться игнорировать.
Шаблон
Хотя нет никакой разницы с
init
и другими методами, то есть разница , как только вы определяете класс фабрики.Эти два не эквивалентны:
Вы хотите вторую форму. Если вы привыкли печатать
instancetype
в качестве возвращаемого типа конструктора, вы каждый раз будете делать это правильно.консистенция
Наконец, представьте, если вы соберете все это вместе: вам нужна
init
функция, а также фабрика классов.Если вы используете
id
дляinit
, вы получите код, подобный этому:Но если вы используете
instancetype
, вы получите это:Это более последовательно и более читабельно. Они возвращают то же самое, и теперь это очевидно.
Вывод
Если вы намеренно не пишете код для старых компиляторов, вы должны использовать его в
instancetype
случае необходимости.Вы должны сомневаться, прежде чем писать сообщение, которое возвращается
id
. Спросите себя: это возвращает экземпляр этого класса? Если это так, этоinstancetype
.Конечно, есть случаи, когда вам нужно вернуться
id
, но вы, вероятно, будете использовать ихinstancetype
гораздо чаще.источник
instancetype
противid
действительно не решение стиля. Недавние измененияinstancetype
действительно проясняют, что мы должны использоватьinstancetype
в таких местах,-init
где мы подразумеваем «экземпляр моего класса»Приведенных выше ответов более чем достаточно, чтобы объяснить этот вопрос. Я просто хотел бы добавить пример для читателей, чтобы понять его с точки зрения кодирования.
ClassA
Класс б
TestViewController.m
источник
Вы также можете получить подробную информацию в назначенном инициализаторе
**
INSTANCETYPE
** Это ключевое слово может использоваться только для типа возвращаемого значения, которое соответствует типу получателя. Метод init всегда объявляется как возвращающий тип экземпляра. Почему бы не сделать, например, возвращаемый тип Party для party party? Это вызвало бы проблему, если бы класс партии был когда-либо подклассом. Подкласс будет наследовать все методы от Party, включая инициализатор и его тип возврата. Если экземпляру подкласса было отправлено это сообщение инициализатора, что будет возвращено? Не указатель на экземпляр Party, а указатель на экземпляр подкласса. Вы можете подумать, что это не проблема, я переопределю инициализатор в подклассе, чтобы изменить тип возвращаемого значения. Но в Objective-C вы не можете иметь два метода с одним и тем же селектором и разными типами возвращаемых данных (или аргументами). Указывая, что метод инициализации возвращает "
МНЕ БЫ
** Перед тем, как тип экземпляра был введен в Objective-C, инициализаторы возвращают id (eye-dee). Этот тип определяется как «указатель на любой объект». (id очень похож на void * в C.) На момент написания, шаблоны классов XCode по-прежнему используют id в качестве возвращаемого типа инициализаторов, добавленных в шаблонный код. В отличие от instancetype, id может использоваться как нечто большее, чем просто возвращаемый тип. Вы можете объявить переменные или параметры метода типа id, если вы не уверены, на какой тип объекта будет указывать переменная. Вы можете использовать id при использовании быстрого перечисления для перебора массива объектов нескольких или неизвестных типов. Обратите внимание: поскольку идентификатор не определен как «указатель на любой объект», вы не включаете * при объявлении переменной или параметра объекта этого типа.
источник