2010-10-23 3 views
2

Я слышал, что когда у вас есть подкласс, вы должны инициализировать суперкласс с той же функцией init изнутри init. Я имею в виду, что init для подкласса должен вызывать [super init], а initWithFrame подкласса должен вызывать [super initWithFrame]. Почему это? Почему вызов супер-init из initWithFrame подкласса приводит к бесконечному циклу?Почему инициализация подклассов требует вызова суперэлемента той же функции init?

Если это необходимо, значит ли это, что я не могу создать новую функцию init внутри подкласса, такую ​​как initWithPoint, и иметь этот вызов super init или initWithFrame просто потому, что у суперкласса нет initWithPoint? Я предполагаю, что суть вопроса заключается в том, почему неправильно назвать другой суперкласс, что меня пугает, возможно, из-за моего фона на C++?

ответ

3

Когда вы создаете подкласс, если вы реализуете инициализатор, вы должны обязательно вызвать назначенный инициализатор (ы) суперкласса, и вы должны указать хотя бы один назначенный инициализатор, хотя это может быть только ваш переопределение суперкласса.

В качестве части инициализации вашего подкласса необходимо вызвать один из назначенных инициализаторов суперкласса.

Документация класса должна назначать назначенные им инициализаторы. Если нет, назначенный инициализатор обычно считается наиболее специфическим инициализатором (который принимает большинство аргументов), предоставляемым суперклассом.

Для получения дополнительной информации см. "The Objective-C Programming Language: Allocating and Initializing Objects."[Примечание: по состоянию на декабрь 2013 года этот контент больше не доступен через центр документации Apple. Что ссылка язык был заменен на более проблемно-ориентированных учебников и концептуальной документации]

Что касается ваших конкретных вопросов:.

Почему это? Чтобы суперкласс имел возможность инициализировать свое состояние. Вы можете продолжить и инициализировать состояние, которое вы добавляете выше и выше того, что обеспечивает суперкласс.

Почему вызов init супер из initWithFrame подкласса приводит к бесконечному циклу? Потому что для NSView, -init не является назначенным инициализатором, хотя это NSObject. Таким образом, NSView переопределяет его для вызова его назначенного инициализатора, -initWithFrame:. Если вы назвали -init от вашего -initWithFrame:, теперь у вас есть -initWithFrame: вызов -init вызова -initWithFrame: вызова -init: призывающих ...

Означает ли это ...? Нет, потому что это не требуется. Вы должны понимать фактическую документацию, а не понаслышке.

+0

Я пробовал просмотреть содержимое ссылки для проверки вашего первого абзаца, ссылка не работает. Однако вот мой аргумент: «должен переопределить назначенный инициализатор (ы) суперкласса», звучит излишне (и, следовательно, звучит неверно). Возьмем, например, подкласс UIView, называемый «NamedUIView», где я просто добавляю свойство NSString, называемое именем. Я просто могу: NamedUIView * myView = [[NamedUIView alloc] init]; [myView setName: @ "JeremysView"]. И это будет прекрасно. Мне не нужно переопределять метод init UIView в файле .m-файла NamedUIView, так как в него нечего добавить – pnizzle

+0

Да, Apple любит играть в прятки с URL-адресами. У них, похоже, нет ничего эквивалентного оригиналу; у них была спецификация языка, но теперь у них есть только учебники. Я отредактировал ответ, чтобы уточнить, когда вам нужно переопределить. –

0

Я не знаю, откуда вы это слышали, но AFAIK это не требуется. Вы можете выбрать подзаголовок, который вы хотите, при условии, что вы вызываете метод init для суперкласса. Любой метод init будет работать.

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

3

Почему это? Почему вызов супер-init из initWithFrame подкласса приводит к бесконечному циклу?

Если -init в супер реализован как

-(id)init { 
    return [self initWithFrame:CGRectZero]; 
} 

тогда граф вызовов будет петля вокруг:

[subclass initWithFrame:] 
    | ^
    v  | 
[super init] 

, как self всегда использует текущий класс ("подкласс").


Если это требуется, то ли это означает, что я не могу создать новую инициализации функцию в подклассе, такие как initWithPoint и есть инициализации, которые называют супер или в initWithFrame просто потому, что супер класс не имеет initWithPoint?

Нет, этого не требуется. Наиболее предпочтительным является вызов самого специализированного инициализатора , поэтому нет никаких шансов, что супер -initXXX переводит -initYYY подкласса.

+0

Это лучшее объяснение бесконечного цикла. –

1

из C++ перспектива:

Я слышал, что когда у вас есть подкласс, вы должны инициализировать суперкласс с тем же инициализации функции внутри инициализации подкласса. Я имею в виду, что init для подкласса должен вызывать [super init], а initWithFrame подкласса должен вызывать [super initWithFrame].

это неправда. это просто обычное дело. вы можете вызывать любой инициализатор суперкласса, который документирован как действительный инициализатор.

это может помочь просмотреть его вот так: Посмотрите на initalizers суперкласса и определите, какие из них поддерживаются.

  • иногда есть назначенный инициализатор
  • иногда появляется новые Инициализаторы (например, один, который может добавить аргумент в супер-суперкласс)
  • иногда бывают инициализаторы унаследованных от супер-суперкласс

для назначенных инициализаторов: считают защищенным

для нового инициализатора: считают защищенным

наследуемых инициализаторов: обычно считают частной, когда суперкласс объявляет новые инициализаторы, иначе защищенный

Почему вызов инициализации супер от initWithFrame результата подкласса в бесконечном цикле?

такой эффект (неопределенное поведение) вызова intializer, который вы не должны вызывать.

Если это требуется, то ли это означает, что я не могу создать новую функцию инициализации в пределах подкласса, таких как initWithPoint и есть инициализации, которые называют супер или в initWithFrame просто потому, что супер класс не имеет initWithPoint?

Это нормально, если вы вызываете один из поддерживаемых инициализаторов суперкласса.

Я думаю, что суть вопроса заключается в том, почему это неправильно, чтобы назвать другой суперкласс, что-то меня путает, возможно, из-за моего фона C++?

objc не поддерживает скрытие/видимость для инициализаторов. как только он находится в интерфейсе суперкласса, он есть (и вы можете делать плохие варианты, когда компилятор не может вам помочь) - вы должны определить график видимости для инициализаторов и соответственно записать свой подкласс. В objc отсутствуют языковые функции, которые вы привыкли иметь на C++.

3

Почему вызов init супер из initWithFrame подкласса приводит к бесконечному циклу?

Исходя из фона C++, как вы говорите, основная проблема, вероятно, в том, что вы привыкли к методу C++, вызывающему парадигму. В Objective-C вы не вызываете функции объектов. Даже технически совершенно правильно сказать, что вы вызываете методы. В Objective-C вы отправляете сообщения объектам, и объект решает, что с ними делать. То, что он обычно делает, - это найти метод в своем классе и вызвать его. Следствием этого является то, что вы не можете контролировать, какая версия метода в иерархии классов вызывается сообщением. Это всегда метод, принадлежащий классу объекта, к которому вы отправляете сообщение (за исключением одного случая). Это как если бы у C++ не было никаких виртуальных функций, даже конструкторов.

Единственное исключение - это когда вы отправляете сообщение супер. В этом случае метод вашего класса обходит. Это может привести к бесконечным циклам, как вы узнали. Причина в том, что мы не вызываем функции, мы отправляем сообщения. Поэтому, если метод A в классе SubKlass отправляет [super methodB], будет задействована реализация метода B в Klass. Если он затем отправляет [self methodA], то я все еще являюсь экземпляром SubKlass, он не волшебным образом не превращается в экземпляр класса Klass, поэтому методA в SubKlass будет вызываться.

Вот почему правила для инициализаторов кажутся настолько запутанными. Только назначенный инициализатор гарантированно не отправляет один из других инициализаторов, поэтому вы можете только безопасно отправить назначенный инициализатор в супер в своем инициализаторе.

Смежные вопросы