objective c - Melhor maneira de definir métodos privados para uma classe no Objective-C




cocoa code-completion (8)

Como outras pessoas disseram, definir métodos privados no bloco @implementation é OK para a maioria dos propósitos.

Sobre o tema da organização do código - Eu gosto de mantê-los juntos sob pragma mark private para facilitar a navegação no Xcode

@implementation MyClass 
// .. public methods

# pragma mark private 
// ...

@end

Eu comecei a programar Objective-C e, tendo um background em Java, me pergunto como as pessoas que escrevem programas Objective-C lidam com métodos privados.

Eu entendo que pode haver várias convenções e hábitos e pense sobre essa questão como um agregador das melhores técnicas que as pessoas usam lidando com métodos privados em Objective-C.

Por favor, inclua um argumento para sua abordagem ao publicá-lo. Por que isso é bom? Que desvantagens tem (que você conhece) e como você lida com elas?

Quanto às minhas descobertas até agora.

É possível usar categories [por exemplo, MyClass (Private)] definidas no arquivo MyClass.m para agrupar métodos privados.

Essa abordagem tem 2 problemas:

  1. Xcode (e compilador?) Não verifica se você define todos os métodos na categoria privada no bloco @implementation correspondente
  2. Você tem que colocar @interface declarando sua categoria privada no início do arquivo MyClass.m, caso contrário, o Xcode reclama com uma mensagem como "auto pode não responder à mensagem" privateFoo ".

O primeiro problema pode ser contornado com categoria vazia [por exemplo, MyClass ()].
O segundo me incomoda muito. Gostaria de ver métodos privados implementados (e definidos) perto do final do arquivo; Eu não sei se isso é possível.


Definir seus métodos privados no bloco @implementation é ideal para a maioria das finalidades. O Clang vai ver isso dentro da @implementation , independentemente da ordem 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 static são muito boas para métodos privados particularmente sensíveis ou de alta velocidade.

Uma convenção para nomear prefixos pode ajudá-lo a evitar a substituição acidental de métodos privados (acho o nome da classe como um prefixo seguro).

As categorias nomeadas (por exemplo, @interface MONObject (PrivateStuff) ) não são uma ideia particularmente boa por causa das potenciais colisões de nomes durante o carregamento. Eles são realmente úteis apenas para amigos ou métodos protegidos (que raramente são uma boa escolha). Para garantir que você seja avisado sobre implementações de categoria incompletas, você deve implementá-lo:

@implementation MONObject (PrivateStuff)
...HERE...
@end

Aqui está uma pequena folha de notas anotada:

MONObject.h

@interface MONObject : NSObject

// public declaration required for clients' visibility/use.
@property (nonatomic, assign, readwrite) bool publicBool;

// public declaration required for clients' visibility/use.
- (void)publicMethod;

@end

MONObject.m

@interface MONObject ()
@property (nonatomic, assign, readwrite) bool privateBool;

// you can use a convention where the class name prefix is reserved
// for private methods this can reduce accidental overriding:
- (void)MONObject_privateMethod;

@end

// The potentially good thing about functions is that they are truly
// inaccessible; They may not be overridden, accidentally used,
// looked up via the objc runtime, and will often be eliminated from
// backtraces. Unlike methods, they can also be inlined. If unused
// (e.g. diagnostic omitted in release) or every use is inlined,
// they may be removed from the binary:
static void PrivateMethod(MONObject * pObject) {
    pObject.privateBool = true;
}

@implementation MONObject
{
    bool anIvar;
}

static void AnotherPrivateMethod(MONObject * pObject) {
    if (0 == pObject) {
        assert(0 && "invalid parameter");
        return;
    }

    // if declared in the @implementation scope, you *could* access the
    // private ivars directly (although you should rarely do this):
    pObject->anIvar = true;
}

- (void)publicMethod
{
    // declared below -- but clang can see its declaration in this
    // translation:
    [self privateMethod];
}

// no declaration required.
- (void)privateMethod
{
}

- (void)MONObject_privateMethod
{
}

@end

Outra abordagem que pode não ser óbvia: um tipo C ++ pode ser muito rápido e fornecer um grau muito maior de controle, enquanto minimiza o número de métodos objc exportados e carregados.


Há um benefício de ausência de métodos privados. Você pode mover a lógica que pretende ocultar para a classe separada e usá-la como delegada. Nesse caso, você pode marcar o objeto delegado como particular e não será visível de fora. Mover a lógica para a classe separada (talvez várias) faz melhor design do seu projeto. Porque suas aulas se tornam mais simples e seus métodos são agrupados em classes com nomes próprios.


Mais uma coisa que eu não vi mencionada aqui - o Xcode suporta arquivos .h com "_private" no nome. Vamos dizer que você tem uma classe MyClass - você tem MyClass.m e MyClass.h e agora você também pode ter MyClass_private.h. O Xcode reconhecerá isso e incluirá na lista de "Contrapartes" no Editor do Assistente.

//MyClass.m
#import "MyClass.h"
#import "MyClass_private.h"

Não há como contornar a questão # 2. É assim que funciona o compilador C (e, portanto, o compilador Objective-C). Se você usar o editor XCode, o popup de função deverá facilitar a navegação dos blocos @implementation e @implementation no arquivo.


Se você quisesse evitar o bloco @interface no topo, você poderia sempre colocar as declarações privadas em outro arquivo MyClassPrivate.h não ideal, mas não MyClassPrivate.h a implementação.

MyClass.h

interface MyClass : NSObject {
 @private
  BOOL publicIvar_;
  BOOL privateIvar_;
}

@property (nonatomic, assign) BOOL publicIvar;
//any other public methods. etc
@end

MyClassPrivate.h

@interface MyClass ()

@property (nonatomic, assign) BOOL privateIvar;
//any other private methods etc.
@end

MyClass.m

#import "MyClass.h"
#import "MyClassPrivate.h"
@implementation MyClass

@synthesize privateIvar = privateIvar_;
@synthesize publicIvar = publicIvar_;

@end

Você poderia usar blocos?

@implementation MyClass

id (^createTheObject)() = ^(){ return [[NSObject alloc] init];};

NSInteger (^addEm)(NSInteger, NSInteger) =
^(NSInteger a, NSInteger b)
{
    return a + b;
};

//public methods, etc.

- (NSObject) thePublicOne
{
    return createTheObject();
}

@end

Estou ciente de que esta é uma pergunta antiga, mas é uma das primeiras que encontrei quando procurava uma resposta para essa mesma pergunta. Eu não vi essa solução discutida em nenhum outro lugar, então deixe-me saber se há algo de tolo em fazer isso.


todos os objetos no Objective C estão em conformidade com o protocolo NSObject, que se mantém no método performSelector:. Eu também estava procurando uma maneira de criar alguns métodos "auxiliares ou particulares" que não precisassem ser expostos em nível público. Se você quiser criar um método privado sem sobrecarga e não ter que defini-lo no seu arquivo de cabeçalho, dê uma chance a ele ...

defina o seu método com uma assinatura semelhante ao código abaixo ...

-(void)myHelperMethod: (id) sender{
     // code here...
}

então quando você precisar referenciar o método, simplesmente chame-o como um seletor ...

[self performSelector:@selector(myHelperMethod:)];

essa linha de código invocará o método que você criou e não terá um aviso irritante sobre não tê-lo definido no arquivo de cabeçalho.





code-completion