Comecei a programar o Objective-C e, tendo experiência em Java, me pergunto como as pessoas que escrevem programas Objective-C lidam com métodos privados.
Entendo que pode haver várias convenções e hábitos e penso sobre essa questão como um agregador das melhores técnicas que as pessoas usam para lidar com métodos privados no Objective-C.
Inclua um argumento para sua abordagem ao publicá-la. Por que isso é bom? Quais são as desvantagens (que você conhece) e como você lida com elas?
Quanto às minhas descobertas até agora.
É possível usar categorias [por exemplo, MyClass (Private)] definidas no arquivo MyClass.m para agrupar métodos privados.
Essa abordagem tem 2 problemas:
- Xcode (e compilador?) Não verifica se você define todos os métodos na categoria privada no bloco @implementation correspondente
- Você deve colocar @interface declarando sua categoria privada no início do arquivo MyClass.m, caso contrário, o Xcode se queixará de uma mensagem como "o self pode não responder à mensagem" privateFoo ".
A primeira edição pode ser contornada com a categoria vazia [por exemplo, MyClass ()].
O segundo me incomoda muito. Eu gostaria de ver métodos privados implementados (e definidos) perto do final do arquivo; Não sei se isso é possível.
fonte
Respostas:
Como já foi dito, não existe um método privado no Objective-C. No entanto, a partir do Objective-C 2.0 (ou seja, Mac OS X Leopard, iPhone OS 2.0 e posterior), você pode criar uma categoria com um nome vazio (por exemplo
@interface MyClass ()
) chamado Extensão de Classe . O que é único em uma extensão de classe é que as implementações de métodos devem ser iguais@implementation MyClass
às dos métodos públicos. Então eu estruturo minhas classes assim:No arquivo .h:
E no arquivo .m:
Eu acho que a maior vantagem dessa abordagem é que ela permite agrupar suas implementações de método por funcionalidade, não pela distinção público / privada (às vezes arbitrária).
fonte
if (bSizeDifference && [self isSizeDifferenceSignificant:fWidthCombined])...
Cometi esse erro e o compilador ficou confuso até que aninhei uma chamada como esta: Então o fWidthCombined estava sempre chegando como 0. #Não existe realmente um "método privado" no Objective-C, se o tempo de execução puder determinar qual implementação usar, ele fará. Mas isso não quer dizer que não haja métodos que não façam parte da interface documentada. Para esses métodos, acho que uma categoria é boa. Em vez de colocar o
@interface
arquivo no topo do arquivo .m como seu ponto 2, eu o colocaria em seu próprio arquivo .h. Uma convenção que sigo (e já vi em outros lugares, acho que é uma convenção da Apple, já que o Xcode agora oferece suporte automático a ela) é nomear esse arquivo após sua classe e categoria com um + separando-os, para que@interface GLObject (PrivateMethods)
possa ser encontrado emGLObject+PrivateMethods.h
. O motivo para fornecer o arquivo de cabeçalho é para que você possa importá-lo em suas classes de teste de unidade :-).A propósito, no que diz respeito à implementação / definição de métodos perto do final do arquivo .m, você pode fazer isso com uma categoria implementando a categoria na parte inferior do arquivo .m:
ou com uma extensão de classe (o que você chama de "categoria vazia"), basta definir esses métodos por último. Os métodos Objective-C podem ser definidos e usados em qualquer ordem na implementação; portanto, não há nada para impedir que você coloque os métodos "privados" no final do arquivo.
Mesmo com extensões de classe, muitas vezes crio um cabeçalho separado (
GLObject+Extension.h
) para que eu possa usar esses métodos, se necessário, imitando a visibilidade "amigo" ou "protegido".Desde que esta resposta foi originalmente escrita, o compilador clang começou a fazer duas passagens pelos métodos Objective-C. Isso significa que você pode evitar declarar completamente seus métodos "particulares" e, se eles estão acima ou abaixo do site de chamada, eles serão encontrados pelo compilador.
fonte
Embora eu não seja especialista em Objective-C, eu apenas defino o método na implementação da minha classe. Concedido, ele deve ser definido antes (acima) de quaisquer métodos que o chamem, mas definitivamente exige a menor quantidade de trabalho a ser feito.
fonte
Definir seus métodos particulares no
@implementation
bloco é ideal para a maioria dos propósitos. Clang verá isso dentro da ordem@implementation
, independentemente da declaração. Não há necessidade de declará-los em uma continuação de classe (também conhecida como extensão de classe) ou categoria nomeada.Em alguns casos, você precisará declarar o método na continuação da classe (por exemplo, se estiver usando o seletor entre a continuação da classe e a
@implementation
).static
funções são muito boas para métodos particulares particularmente sensíveis ou críticos para a velocidade.Uma convenção para nomear prefixos pode ajudar a evitar a substituição acidental de métodos privados (acho o nome da classe um prefixo seguro).
As categorias nomeadas (por exemplo
@interface MONObject (PrivateStuff)
) não são uma ideia particularmente boa devido a possíveis colisões de nomes durante o carregamento. Eles são realmente úteis apenas para métodos protegidos ou amigos (que raramente são uma boa escolha). Para garantir que você seja avisado sobre implementações de categorias incompletas, você deve realmente implementá-lo:Aqui está uma pequena folha de dicas anotadas:
MONObject.h
MONObject.m
Outra abordagem que pode não ser óbvia: um tipo C ++ pode ser muito rápido e fornecer um grau de controle muito mais alto, minimizando o número de métodos objc exportados e carregados.
fonte
Você pode tentar definir uma função estática abaixo ou acima da sua implementação que leva um ponteiro para sua instância. Ele poderá acessar qualquer uma das variáveis da sua instância.
fonte
Você poderia usar blocos?
Estou ciente de que esta é uma pergunta antiga, mas é uma das primeiras que encontrei quando procurava uma resposta para essa pergunta. Eu não vi essa solução discutida em nenhum outro lugar; então, deixe-me saber se há algo tolo em fazer isso.
fonte
static
). Mas eu tenho experimentado atribuir blocos a ivars privados (a partir do método init) - tipo JavaScript - que também permite acesso a ivars privados, algo que não é possível a partir de funções estáticas. Ainda não tenho certeza do que eu prefiro.todos os objetos no Objetivo C estão em conformidade com o protocolo NSObject, que se mantém no método performSelector:. Eu também procurava anteriormente uma maneira de criar alguns métodos "auxiliares ou particulares" que não precisavam ser expostos em nível público. Se você deseja criar um método privado sem sobrecarga e sem precisar defini-lo no arquivo de cabeçalho, experimente ...
defina o seu método com uma assinatura semelhante ao código abaixo ...
quando precisar fazer referência ao método, basta chamá-lo como seletor ...
essa linha de código chamará o método que você criou e não terá um aviso irritante sobre não tê-lo definido no arquivo de cabeçalho.
fonte
Se você quiser evitar o
@interface
bloco na parte superior, sempre poderá colocar as declarações privadas em outro arquivo,MyClassPrivate.h
não o ideal, mas não sobrecarregando a implementação.MyClass.h
MyClassPrivate.h
MyClass.m
fonte
Mais uma coisa que não vi mencionada aqui - o Xcode suporta arquivos .h com "_private" no nome. Digamos que você tenha uma classe MyClass - você tem MyClass.m e MyClass.he agora você também pode ter MyClass_private.h. O Xcode reconhecerá isso e o incluirá na lista de "homólogos" no Editor Assistente.
fonte
Não há como contornar o problema nº 2. É assim que o compilador C (e, portanto, o compilador Objective-C) funciona. Se você usar o editor XCode, o pop-up da função deve facilitar a navegação nos blocos
@interface
e@implementation
no arquivo.fonte
Há um benefício da ausência de métodos privados. Você pode mover a lógica que pretendia ocultar para a classe separada e usá-la como delegada. Nesse caso, você pode marcar o objeto delegado como privado e não será visível de fora. Mover a lógica para a classe separada (talvez várias) cria um melhor design do seu projeto. Porque suas classes se tornam mais simples e seus métodos são agrupados em classes com nomes próprios.
fonte
Como outras pessoas disseram, definir métodos privados no
@implementation
bloco é bom para a maioria dos propósitos.Sobre o tema da organização de código - eu gosto de mantê-los juntos
pragma mark private
para facilitar a navegação no Xcodefonte