Pergunta

Ouvi dizer que, quando você tem uma subclasse, você deve inicializar a superclasse com a mesma função init do init da subclasse. O que quero dizer é que o init da subclasse deve chamar [Super Init] e o InitWithFrame do subclasse deve chamar [super initwithframe]. Por que é isso? Por que chamar o init do super do InitWithFrame de uma subclasse resulta em um loop infinito?

Se isso for necessário, isso significa que não posso criar uma nova função init em uma subclasse como o InitWithPoint e ter o Init ou initwithframe de chamadas de Super simplesmente porque a Super Class não tem InitwithPoint? Eu acho que o coração da pergunta aqui é simplesmente por que é impróprio chamar uma super classe diferente, algo que está me confundindo possivelmente por causa do meu fundo C ++?

Foi útil?

Solução

Quando você cria uma subclasse, se você implementar um inicializador, deverá ligar para o (s) inicial (s) (s) (s) (s) (s) Superclasse (s) (s) (s)) (s) (s) (s) seu .

Como parte da inicialização da sua subclasse, você deve chamar um dos inicializadores designados da Superclass.

A documentação de uma classe deve nomear seus inicializadores designados. Caso contrário, o inicializador designado é geralmente assumido como o inicializador mais específico (o que mais aproveita os argumentos) fornecido pela superclasse.

Para mais detalhes, consulte "A linguagem de programação Objective-C: alocando e inicializando objetos". Nota: em dezembro de 2013, esse conteúdo não parece mais estar disponível no centro de documentos da Apple. O que foi uma referência de idioma foi substituída por tutoriais mais orientados a tarefas e documentação conceitual.

Quanto às suas perguntas específicas:

Por que é isso? Para que a superclasse tenha a chance de inicializar seu estado. Você pode seguir em frente e inicializar o estado que adiciona acima e além do que a superclasse fornece.

Por que chamar o init do super do InitWithFrame de uma subclasse resulta em um loop infinito? Por causa de NSView, -init não é o inicializador designado, embora seja NSObject's. Então NSView substitui para chamar seu inicializador designado, -initWithFrame:. Se você ligou -init de você -initWithFrame:, agora você tem -initWithFrame: chamando -init chamando -initWithFrame: chamando -init: Chamando ...

Isso significa…? Não, porque isso não é necessário. Você deve entender a documentação real, não boatos.

Outras dicas

Por que é isso? Por que chamar o init do super do InitWithFrame de uma subclasse resulta em um loop infinito?

Se o -init em super é implementado como

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

Em seguida, o gráfico de chamadas vai percorrer:

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

Como self sempre usa a classe atual ("subclasse").


Se isso for necessário, isso significa que não posso criar uma nova função init em uma subclasse como o InitWithPoint e ter o Init ou initwithframe de chamadas de Super simplesmente porque a Super Class não tem InitwithPoint?

Não, isso não é necessário. O que é preferido é ligar superé o inicializador mais especializado, então não há chance de super -initXXX chama de volta a subclasse -initYYY.

Por que chamar o init do super do InitWithFrame de uma subclasse resulta em um loop infinito?

Vindo de um plano de fundo C ++, como você diz que faz, o principal problema é provavelmente que você está acostumado com o paradigma do método C ++. No Objective-C, você não chama funções de objetos. Nem sequer é tecnicamente completamente correto dizer que você invoca métodos. No Objective-C, você envia mensagens para objetos e o objeto decide o que fazer com eles. O que normalmente faz é procurar um método em sua classe e invocar isso. A conseqüência disso é que você não pode controlar qual versão de um método em uma hierarquia de classe é invocada por uma mensagem. É sempre o método pertencente à classe do objeto para o qual você envia a mensagem (exceto em um caso). É como se o C ++ não tivesse funções não virtuais, nem mesmo os construtores.

A única exceção é quando você envia uma mensagem para super. Nesse caso, o método da sua classe é ignorado. Isso pode levar a loops infinitos, como você descobriu. O motivo é porque não chamamos funções, enviamos mensagens. Então, se o Methoda na classe subklass enviar [super methodB] A implementação do MethodB no Klass será invocada. Se ele enviar [self methodA] O Self ainda é uma instância de subklass, ele não se transformou magicamente em uma instância de Klass; portanto, o Methoda na subklass será invocado.

É por isso que as regras para os iniciantes parecem tão complicados. Somente o inicializador designado é garantido para não enviar um dos outros iniciantes, para que você possa enviar apenas com segurança o inicializador designado para super no seu inicializador.

De uma perspectiva C ++:

Ouvi dizer que, quando você tem uma subclasse, você deve inicializar a superclasse com a mesma função init do init da subclasse. O que quero dizer é que o init da subclasse deve chamar [Super Init] e o InitWithFrame do subclasse deve chamar [super initwithframe].

isso não é verdade. é meramente comum. Você está livre para chamar qualquer inicializador de superclass que seja documentado como um inicializador válido.

Pode ajudar a visualizá -lo assim: observe os inativadores da Superclass e a determinar quais são suportados.

  • Às vezes há um inicializador designado
  • Às vezes, existem novos inicializadores (por exemplo, um que pode adicionar um argumento à super-superclasse)
  • Às vezes, existem intializadores herdados da super-superclasse

Para inicializadores designados: considere protegido

Para o novo inicializador: considere protegido

Para inicializadores herdados: tipicamente Considere privado quando a superclasse declara novos inicializadores, de outra forma protegidos

Por que chamar o init do super do InitWithFrame de uma subclasse resulta em um loop infinito?

Esse é o efeito (comportamento indefinido) de chamar um intializador que você não deve ligar.

Se isso for necessário, isso significa que não posso criar uma nova função init em uma subclasse como o InitWithPoint e ter o Init ou initwithframe de chamadas de Super simplesmente porque a Super Class não tem InitwithPoint?

Isso é bom, desde que você chame através de um dos inicializadores de superclasse suportados.

Eu acho que o coração da pergunta aqui é simplesmente por que é impróprio chamar uma super classe diferente, algo que está me confundindo possivelmente por causa do meu fundo C ++?

O OBJC não suporta ocultação/visibilidade para inicializadores. Uma vez que está na interface de uma superclasse, ela está lá (e você pode fazer más escolhas em que o compilador não pode ajudá -lo) - espera -se que determine o gráfico de visibilidade dos inicializadores e escreva sua subclasse de acordo. O OBJC não tem recursos de linguagem que você está acostumado a ter no C ++.

Não sei de onde você ouviu, mas não é necessário. Você pode optar por iniciar sua subclasse com o que quiser, desde que você chame um método init da superclasse. Qualquer método init funcionará.

No entanto, se você também tem a mesma função init em sua superclasse, acho que a melhor coisa a fazer é chamar essa função e adicionar sua própria personalização. Não é necessário, é apenas uma boa prática fazê -lo, porque essa função init pode fornecer algumas inicializações e configurações que você pode esquecer de adicionar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top