Eu já vi várias estratégias para declarar métodos semi-privados no Objective-C , mas não parece haver uma maneira de criar um método verdadeiramente privado. Eu aceito isso. Mas, por que isso é assim? Todas as explicações que eu essencialmente digo, "você não pode fazê-lo, mas aqui está uma aproximação aproximada".
Há um número de palavras-chave aplicado a ivars
(membros) que controlam o seu âmbito, por exemplo @private
, @public
, @protected
. Por que isso não pode ser feito para métodos também? Parece algo que o tempo de execução deve suportar. Há uma filosofia subjacente que estou perdendo? Isso é deliberado?
objective-c
objective-c-runtime
Rob Jones
fonte
fonte
Respostas:
A resposta é ... bem ... simples. Simplicidade e consistência, de fato.
O Objective-C é puramente dinâmico no momento do envio do método. Em particular, todo envio de método passa exatamente pelo mesmo ponto de resolução de método dinâmico que qualquer outro envio de método. No tempo de execução, toda implementação de método tem exatamente a mesma exposição e todas as APIs fornecidas pelo tempo de execução Objective-C que funcionam com métodos e seletores funcionam igualmente da mesma forma em todos os métodos.
Como muitos responderam (aqui e em outras perguntas), os métodos privados em tempo de compilação são suportados; se uma classe não declarar um método em sua interface disponível ao público, esse método também pode não existir no que diz respeito ao seu código. Em outras palavras, você pode obter todas as várias combinações de visibilidade desejadas no momento da compilação, organizando seu projeto adequadamente.
Há pouco benefício em duplicar a mesma funcionalidade no tempo de execução. Isso acrescentaria uma quantidade enorme de complexidade e sobrecarga. E mesmo com toda essa complexidade, ainda assim não impediria que todos, exceto o desenvolvedor mais casual, executassem seus métodos supostamente "privados".
Fazer isso, porém, minaria a pura natureza dinâmica da linguagem. Todo envio de método não passaria mais por um mecanismo de envio idêntico. Em vez disso, você ficaria em uma situação em que a maioria dos métodos se comporta de uma maneira e um pequeno punhado é apenas diferente.
Isso se estende além do tempo de execução, pois existem muitos mecanismos no cacau construídos sobre o dinamismo consistente do Objective-C. Por exemplo, tanto a codificação de valores-chave quanto a observação de valores-chave precisariam ser muito modificadas para dar suporte a métodos privados - provavelmente criando uma brecha explorável - ou métodos privados seriam incompatíveis.
fonte
O tempo de execução poderia suportar, mas o custo seria enorme. Todo seletor enviado deve ser verificado se é privado ou público para essa classe, ou cada classe precisará gerenciar duas tabelas de expedição separadas. Isso não é o mesmo para variáveis de instância, porque esse nível de proteção é feito em tempo de compilação.
Além disso, o tempo de execução precisaria verificar se o remetente de uma mensagem privada é da mesma classe que o destinatário. Você também pode ignorar métodos privados; se a classe utilizada
instanceMethodForSelector:
, poderia retornar o retornoIMP
a qualquer outra classe para que eles invocassem o método privado diretamente.Métodos particulares não puderam ignorar o envio da mensagem. Considere o seguinte cenário:
Uma classe
AllPublic
tem um método de instância públicadoSomething
Outra classe
HasPrivate
tem um método de instância privado também chamadodoSomething
Você cria uma matriz que contém qualquer número de instâncias de ambos
AllPublic
eHasPrivate
Você tem o seguinte loop:
Se você executasse esse loop a partir de dentro
AllPublic
, o tempo de execução teria que interromper o enviodoSomething
dasHasPrivate
instâncias, no entanto, esse loop seria utilizável se estivesse dentro daHasPrivate
classe.fonte
As respostas postadas até agora fazem um bom trabalho em responder à pergunta de uma perspectiva filosófica, por isso vou postular uma razão mais pragmática: o que seria ganho com a mudança da semântica da linguagem? É simples o suficiente para "ocultar" métodos privados de maneira eficaz. A título de exemplo, imagine que você tenha uma classe declarada em um arquivo de cabeçalho, assim:
Se você precisar de métodos "particulares", também poderá colocar isso no arquivo de implementação:
Claro, não é exatamente o mesmo que métodos privados C ++ / Java, mas é suficientemente próximo, por que alterar a semântica da linguagem, bem como o compilador, o tempo de execução, etc., para adicionar um recurso que já é emulado de maneira aceitável maneira? Como observado em outras respostas, a semântica de passagem de mensagens - e sua dependência da reflexão em tempo de execução - tornariam o manuseio de mensagens "privadas" não trivial.
fonte
A solução mais fácil é apenas declarar algumas funções C estáticas em suas classes de Objective-C. Eles só têm escopo de arquivo de acordo com as regras C para a palavra-chave estática e, por isso, só podem ser usadas pelos métodos dessa classe.
Sem barulho.
fonte
Sim, isso pode ser feito sem afetar o tempo de execução, utilizando uma técnica já empregada pelo (s) compilador (es) para manipular C ++: manipulação de nomes.
Isso não foi feito porque não foi estabelecido que resolveria uma dificuldade considerável no espaço do problema de codificação que outras técnicas (por exemplo, prefixação ou sublinhado) são capazes de contornar suficientemente. Uau, você precisa de mais dor para superar hábitos arraigados.
Você pode contribuir com patches para clang ou gcc que adicionam métodos privados à sintaxe e geram nomes desconfigurados que somente eles reconhecem durante a compilação (e esquecem-se prontamente). Em seguida, outros membros da comunidade Objective-C poderiam determinar se realmente valia a pena ou não. É provável que seja mais rápido assim do que tentar convencer os desenvolvedores.
fonte
Essencialmente, isso tem a ver com a forma de passagem de mensagens do Objective-C de chamadas de método. Qualquer mensagem pode ser enviada para qualquer objeto, e o objeto escolhe como responder à mensagem. Normalmente, ele responderá executando o método nomeado após a mensagem, mas também poderá responder de várias outras maneiras. Isso não torna os métodos privados completamente impossíveis - o Ruby faz isso com um sistema semelhante de passagem de mensagens -, mas os torna um pouco estranhos.
Até a implementação de métodos privados de Ruby é um pouco confusa para as pessoas devido à estranheza (você pode enviar ao objeto qualquer mensagem que desejar, exceto as desta lista !). Essencialmente, Ruby faz funcionar proibindo que métodos privados sejam chamados com um receptor explícito. No Objective-C, seria necessário ainda mais trabalho, pois o Objective-C não possui essa opção.
fonte
É um problema com o ambiente de tempo de execução do Objective-C. Enquanto o C / C ++ é compilado em código de máquina ilegível, o Objective-C ainda mantém alguns atributos legíveis por humanos, como nomes de métodos como strings . Isso dá ao Objective-C a capacidade de executar recursos reflexivos .
EDIT: Ser uma linguagem reflexiva sem métodos estritos privados torna o Objective-C mais "pitônico", na medida em que você confia em outras pessoas que usam seu código, em vez de restringir quais métodos eles podem chamar. O uso de convenções de nomenclatura, como sublinhado duplo, visa ocultar seu código de um codificador de cliente casual, mas não impede que os codificadores precisem fazer um trabalho mais sério.
fonte
Existem duas respostas, dependendo da interpretação da pergunta.
O primeiro é ocultando a implementação do método da interface. Isso é usado, normalmente com uma categoria sem nome (por exemplo
@interface Foo()
). Isso permite que o objeto envie essas mensagens, mas não outras - embora ainda seja possível substituir acidentalmente (ou não).A segunda resposta, supondo que se trata de desempenho e inclusão, é possível, mas como uma função C local. Se você quisesse um
NSString *arg
método 'private foo ( )', você ovoid MyClass_foo(MyClass *self, NSString *arg)
chamaria como uma função C comoMyClass_foo(self,arg)
. A sintaxe é diferente, mas atua com o tipo de características de desempenho sãs dos métodos privados do C ++.Embora isso responda à pergunta, devo salientar que a categoria sem nome é de longe a maneira mais comum de Objective-C de fazer isso.
fonte
O Objective-C não suporta métodos privados porque não precisa deles.
No C ++, todo método deve estar visível na declaração da classe. Você não pode ter métodos que alguém incluindo o arquivo de cabeçalho não possa ver. Portanto, se você deseja que métodos que o código fora da sua implementação não deva usar, você não tem escolha, o compilador deve fornecer uma ferramenta para que você possa dizer que o método não deve ser usado, ou seja, a palavra-chave "private".
No Objective-C, você pode ter métodos que não estão no arquivo de cabeçalho. Portanto, você alcança o mesmo objetivo com muita facilidade, não adicionando o método ao arquivo de cabeçalho. Não há necessidade de métodos particulares. O Objective-C também tem a vantagem de que você não precisa recompilar todos os usuários de uma classe porque alterou os métodos privados.
Por exemplo, variáveis que você costumava declarar no arquivo de cabeçalho (não mais), @private, @public e @protected estão disponíveis.
fonte
Uma resposta que falta aqui é: porque os métodos privados são uma má ideia do ponto de vista da capacidade de evoluir. Pode parecer uma boa idéia tornar um método privado ao escrevê-lo, mas é uma forma de ligação antecipada. O contexto pode mudar e um usuário posterior pode querer usar uma implementação diferente. Um pouco provocador: "Os desenvolvedores ágeis não usam métodos privados"
De certa forma, assim como o Smalltalk, o Objective-C é para programadores adultos. Valorizamos saber o que o desenvolvedor original assumiu que a interface deva ser e assumimos a responsabilidade de lidar com as consequências, se precisarmos alterar a implementação. Então, sim, é filosofia, não implementação.
fonte