Pergunta

Em Objective-C, eu posso adicionar métodos para classes existentes com uma categoria, por exemplo.

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

É também possível fazer isso com os protocolos, ou seja, se houvesse um protocolo NSString, algo como:

@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

Eu quero fazer isso desde que eu tenho várias extensões para NSObject (a classe), usando métodos NSObject única públicas, e eu quero que essas extensões também ao trabalho com objetos implementação do protocolo.

Para dar mais um exemplo, o que se eu quiser escrever uma logDescription método que imprime a descrição de um objeto para o log:

- (void) logDescription {
    NSLog(@"%@", [self description]);
}

I pode, naturalmente, adicionar esse método para NSObject, mas há outras classes que não herdam NSObject, onde eu também gostaria de ter este método, por exemplo, NSProxy. Como o método utiliza apenas membros públicos de protocolo, seria melhor para adicioná-lo ao protocolo.

Edit: Java 8 agora tem isto com "métodos virtuais de extensão" em interfaces: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf . Este é exatamente o que eu gostaria de fazer em Objective-C. Eu não vi esta pergunta ganhando tanta atenção ...

Saudações, Jochen

Foi útil?

Solução

extObjC tem o material mais puro você pode fazer com Protocolos / categorias ... primeiro fora é @concreteprotocol ...

  • Define um "protocolo de concreto", que pode fornecer implementações padrão de métodos dentro do protocolo.
  • Um bloco @protocol deve existir em um arquivo de cabeçalho, e um bloco @concreteprotocol correspondente em um arquivo de implementação.
  • Qualquer objeto que se declara estar de acordo com este protocolo receberão suas implementações de método, mas apenas se nenhum método com o mesmo nome já existe.

MyProtocol.h

@protocol MyProtocol 
@required - (void)someRequiredMethod;
@optional - (void)someOptionalMethod;
@concrete - (BOOL)isConcrete;   

MyProtocol.m

 @concreteprotocol(MyProtocol) - (BOOL)isConcrete { return YES; } ...

para declarar uma MyDumbObject : NSObject <MyProtocol> objeto voltará automaticamente YES para isConcrete.

Além disso, eles têm pcategoryinterface(PROTOCOL,CATEGORY) que "define a interface para uma categoria chamada CATEGORIA em um protocolo de protocolo". Categorias protocolo conter métodos que são automaticamente aplicados a qualquer classe que se declara estar de acordo com protocolo." Existe uma macro que acompanha você também tem que usar em seu arquivo de implementação. Veja os docs.

Por último, mas não menos importante / não diretamente relacionadas com @protocols é synthesizeAssociation(CLASS, PROPERTY), que "sintetiza uma propriedade para uma classe usando objetos associados. Isto é principalmente útil para adicionar propriedades a uma classe dentro de uma categoria. PROPRIEDADE deve ter sido declarado com @property na interface da classe especificada (ou uma categoria sobre ele), e deve ser do tipo de objeto ".

Muitos das ferramentas nesta biblioteca open (caminho-up) as coisas que você pode fazer com ObjC ... a partir de herança múltipla ... para o bem, sua imaginação é o limite.

Outras dicas

resposta curta: Não.

Long resposta: como é que isso funciona? Imagine que você pode adicionar métodos para protocolos existentes? Como isso funcionaria? Imagine que queria acrescentar outro método para NSCoding, -(NSArray *) codingKeys; dizer que este método é um método necessário que retorna uma matriz das teclas utilizadas para codificar o objeto.

O problema é que existem classes existentes (como, digamos NSString) que já implementam NSCoding, mas não implementam o nosso método codingKeys. O que deve acontecer? Como no quadro da pré-compilados saberia o que fazer quando esta necessário mensagem é enviada para uma classe que não implementá-lo?

Pode-se dizer "podemos acrescentar a definição deste método através de uma categoria" ou "poderíamos dizer que quaisquer métodos adicionados através dessas categorias de protocolo são explicitamente opcional". Sim, você poderia fazer isso e, teoricamente, contornar o problema que eu descrevi acima. Mas se você estiver indo para fazer isso, você pode muito bem fazê-lo uma categoria, em primeiro lugar, e, em seguida, verifique se o respondsToSelector: classe antes de invocar o método.

Embora seja verdade que você não pode definir categorias de protocolos (e não iria querer, porque você não sabe nada sobre o objeto existente), você pode definir categorias de tal forma que o código se aplica somente a um objecto do tipo de dado que tem o protocolo desejado (uma espécie de tipo 's C ++ especialização modelo parcial).

O principal uso para algo como isso é quando você deseja definir uma categoria que depende de uma versão personalizada de uma classe. (Imagine que eu tenho subclasses UIViewController que estejam em conformidade com o protocolo de Foo, o que significa que tem a propriedade foo, o meu código de categoria pode ter necessidade da propriedade foo, mas não posso aplicá-lo para o protocolo Foo, e se eu simplesmente aplicá-lo a UIViewController, o código não será compilado por padrão, e forçando-o a compilar meios alguém fazendo introspecção, ou apenas estragar, pode chamar seu código que depende do protocolo a abordagem híbrida poderia funcionar assim:.

@protocol Foo
- (void)fooMethod

@property (retain) NSString *foo;
@end

@implementation UIViewController (FooCategory)

- (void)fooMethod {
    if (![self conformsToProtocol:@protocol(Foo)]) {
        return;
    }

    UIViewController<Foo> *me = (UIViewController<Foo>*) self;
    // For the rest of the method, use "me" instead of "self"
    NSLog(@"My foo property is \"%@\"", me.foo);
}
@end

Com a abordagem híbrida, você pode escrever o código apenas uma vez (por classe que é suposto para implementar o protocolo) e ter certeza de que isso não afetará as instâncias da classe que não estejam em conformidade com o protocolo.

A desvantagem é que a síntese de propriedade / definição ainda tem que acontecer nas subclasses individuais.

Não é realmente significativo para fazê-lo uma vez que um protocolo não pode realmente implementar o método. Um protocolo é uma forma de declarar que você apoia alguns métodos. Adicionando um método para essa lista fora dos meios de protocolo que todos os "em conformidade" classes acidentalmente declarar o novo método, mesmo que eles não implementá-lo. Se alguma classe implementado o protocolo NSObject mas não descendem de NSObject, e então você adicionou um método para o protocolo, que iria quebrar a conformidade da classe.

Você pode, no entanto, criar um novo protocolo que inclui o antigo com uma declaração como @protocol SpecialObject <NSObject>.

Eu acho que você pode ser misturar termos aqui e ali. Extensões, categorias, protocolos, interfaces e classes são todas as coisas diferentes em Objective-C. Em O Objective-C 2.0 Language a Apple descreve as diferenças muito bem, incluindo os benefícios e desvantagens de usar categorias e extensões.

Se você pensar sobre isso, o que é uma "categoria" ou "Extensão", no sentido conceitual? É uma forma de adicionar funcionalidade a uma classe. Em Objective-C, os protocolos são projetados para ter nenhuma implementação. Portanto, como você adicionar ou estender a implementação de algo que não tem aplicação para começar?

Se você já está escrevendo uma categoria, porque não basta adicionar na definição de protocolo na direita cabeçalho após a definição de categoria?

i.

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

@protocol MyExtendedProtocolName <NSString>
//Method declarations go here
@end

Desta forma, qualquer classe que as importações do cabeçalho categoria também terá a definição de protocolo, e você pode adicioná-lo em sua classe ..

@interface MyClass <OriginalProtocol,MyExtendedProtocolName>

Além disso, deve ter cuidado ao subclasse NSString, é um cluster e você não pode sempre obter o comportamento que você está esperando.

Adam afiada colocaram um solução que funcionou para mim.

Trata-se de 3 etapas:

  1. Definir os métodos que você deseja adicionar como @optional em um protocolo.
  2. Fazer os objetos que você deseja estender em conformidade com esse protocolo.
  3. Copiar esses métodos para esses objetos em tempo de execução.

Confira no link para os detalhes.

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