Como eu posso passar um nome de classe como um argumento para uma fábrica de objeto no cacau?

StackOverflow https://stackoverflow.com/questions/315591

Pergunta

Eu estou trabalhando em uma fábrica de objeto para manter o controle de uma pequena coleção de objetos. Os objetos podem ser de diferentes tipos, mas todos eles vão responder a createInstance e reset. Os objetos não pode ser derivada de uma classe base comum porque alguns deles terão que derivar de classes internas de cacau como NSView e NSWindowController.

Eu gostaria de ser capaz de criar instâncias de qualquer objeto adequado, simplesmente passando o nome da classe desejada para a minha fábrica da seguinte forma:

myClass * variable = [factory makeObjectOfClass:myClass];

O método makeObjectOfClass: seria algo parecido com isto:

- (id)makeObjectOfClass:(CLASSNAME)className
{
    assert([className instancesRespondToSelector:@selector(reset)]);
    id newInstance = [className createInstance];
    [managedObjects addObject:newInstance];
    return newInstance;
}

Existe uma maneira de passar um nome de classe para um método, como eu fiz com o argumento (CLASSNAME)className para makeObjectOfClass: acima?

Por uma questão de exaustividade, aqui é por isso que quero para gerenciar todos os objetos. Eu quero ser capaz de redefinir o conjunto completo de objetos em um tiro, chamando [factory reset];.

- (void)reset
{
    [managedObjects makeObjectsPerformSelector:@selector(reset)];
}
Foi útil?

Solução

Você pode converter uma string para uma classe usando a função: NSClassFromString

Class classFromString = NSClassFromString(@"MyClass");

No seu caso, porém, você seria melhor fora usando a classe objetos diretamente.

MyClass * variable = [factory makeObjectOfClass:[MyClass class]];

- (id)makeObjectOfClass:(Class)aClass
{
    assert([aClass instancesRespondToSelector:@selector(reset)]);
    id newInstance = [aClass createInstance];
    [managedObjects addObject:newInstance];
    return newInstance;
}

Outras dicas

Eu tenho direito de ter um tutorial sobre isso, por favor check-out https://appengineer.in/ 2014/03/13 / send-class-name-como-um-argumento-in-ios /

É muito fácil para especificar dinamicamente uma classe, na verdade, você pode apenas fazer referência a ela por ele é nome:

id string = [[NSClassFromString(@"NSString") alloc] initWithString:@"Hello!"];
NSLog( @"%@", string );

Uma outra dica, gostaria de evitar usando a nomenclatura 'conseguiu objeto' já que a maioria outros programadores de cacau vai ler isso como NSManagedObject, do Core Data. Você também pode achar que é mais fácil usar um NSNotification global (que todos os seus objetos de reset-poder subscrever) em vez de gerenciar uma coleção de diferentes tipos de objetos, mas você está mais informado para tomar essa decisão que eu.

O bit da resposta ausente das outras respostas é que você pode definir um @protocol contendo seus métodos +createInstance e +reset.

Parece que você quer algo como:

- (id)makeObjectOfClassNamed:(NSString *)className
{
    Class klass = NSClassFromString(className);
    assert([klass instancesRespondToSelector:@selector(reset)]);
    id newInstance = [klass createInstance];
    [managedObjects addObject:newInstance];
    return newInstance;
}

Esta assumiria um método de classe chamado +createInstance. Ou você pode simplesmente usar [[klass alloc] init].

Para chamá-lo:

MyClass *variable = [factory makeObjectOfClassNamed:@"MyClass"];

Dependendo do que você está tentando fazer, que poderia ser melhor para passar em torno de objetos de classe do que cordas, por exemplo:.

MyClass *variable = [factory makeObjectOfClass:[MyClass class]];
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top