Pergunta

Observação:Sou relativamente novo em Objective-C e venho de Java e PHP.

Alguém poderia me explicar por que sempre tenho que primeiro alocar e depois inicializar uma instância?

Isso não poderia ser feito nos métodos init como este:

+ (MyClass*)init {
    MyClass *instance = [MyClass alloc];
    [instance setFoo:@"bla"];

    return instance;
}

+ (MyClass*)initWithString:(NSString*)text {
    MyClass *instance = [MyClass init];
    [instance setFoo:text];

    return instance;
}
...

Isso é apenas uma relíquia dos velhos tempos C ou há algo que não estou vendo?

Eu sei que isso não é um problema, pois eu poderia sempre chamar alloc e init, mas como é um pouco tedioso, gostaria de pelo menos saber por que estou fazendo isso.

Estou gostando da expressividade da linguagem até agora, mas isso é algo que quero entender completamente para pensar do jeito Objective-C.

Obrigado!

Foi útil?

Solução

+Novo acaba enviando uma mensagem de alocação +para a classe e uma mensagem -init para o que voltar do +aloc.

A razão pela qual a próxima partiu da convenção de Stepstone de usar a nova mensagem (que era uma idéia de pequeno porte) é que, no início, eles encontraram situações em que queriam poder inicializar o mesmo objeto mais de uma vez.

Outras dicas

Porque criar uma instância e inicializar uma instância são dois trabalhos separados.

Você envia um alloc mensagem para a classe para obter uma instância não inicializada. Você deve inicializar a instância e geralmente tem várias maneiras de fazer isso. Por exemplo:

myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:@"%@.%@", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];

Cada um deles inicializa a string de uma maneira completamente diferente. Como você inicializa a string depende do que você deseja inicializá -la.

Claro, ninguém gosta de escrever alloc e depois init e depois autorelease toda vez, então você geralmente tem métodos de conveniência (por exemplo, stringWithFormat:) que dê as três etapas para você.

Editar: Para saber mais sobre este tópico, incluindo idéias essenciais dos comentaristas, consulte minha postagem no blog “Reunificação”.

Ver NSZone.

+alloc é um corte de atalho para +allocWithZone:, que é um mecanismo que o cacau fornece para otimizar a alocação de memória.

Então você tem a opção de fazer algo assim:

foo = [[NSString allocWithZone:MyZone] initWithString:@"Foo"];
foo2 = [foo copyWithZone:MyZone];

A idéia por trás das zonas de memória é que, se você tiver um grande número de objetos semelhantes que são frequentemente alocados e desalocados, pode ser mais eficiente usar uma zona de memória separada para esses objetos.

Para que o zoneamento seja eficaz, você gostaria de ter +allocWithZone: Disponível para todas as subclasse NSObject, portanto, você precisa separar a alocação e a inicialização. Você pode criar e usar todos os atalhos que deseja, como +new, mas por baixo de tudo, você precisa de um -init Método que inicializa um objeto que já foi alocado.

“Separar os estágios de alocação e inicialização da criação de instâncias oferece muitos benefícios.É possível usar qualquer variação do método de classe +alloc para alocar uma instância e então usar qualquer inicializador disponível com a nova instância. Isso torna possível criar seus próprios métodos de inicialização sem a necessidade de fornecer implementações alternativas de todos os métodos de alocação.Raramente são criados novos métodos de alocação porque os métodos existentes atendem a quase todas as necessidades.Entretanto, um ou mais novos inicializadores são criados para quase todas as classes.Devido à separação dos estágios de alocação e inicialização, as implementações de inicializadores só precisam lidar com as variáveis ​​de novas instâncias e podem ignorar completamente os problemas que envolvem a alocação. A separação simplifica o processo de escrita de inicializadores.Além disso, inicializadores padrão Cocoa como -initWithCoder:trabalhar com instâncias independentemente da forma como a memória da instância foi alocada.Uma consequência negativa da separação entre alocação e inicialização é a necessidade de estar ciente de convenções como o inicializador designado. Você deve saber quais métodos são inicializadores designados e como criar e documentar novos inicializadores em subclasses.No longo prazo, o uso de inicializadores designados simplifica o desenvolvimento de software, mas há um argumento de que o padrão de criação em dois estágios aumenta a curva de aprendizado inicial dos desenvolvedores do Cocoa.


(c) Padrões de Design de Cacau por Erik M.Buck e Donald A.Yacktman

Você não precisa. Você pode usar [MyClass new]. Isso é semelhante ao seu hipotético init método.

Basicamente, o Objective-C, que não teve coleta de lixo inicialmente, separa o conceito de alocação de memória e inicialização da classe. É por isso que existem dois métodos distintos. Quando Você ligar alloc, você está alocando explicitamente a memória.

A maioria das aulas tem o que você está pedindo. Você já recebeu respostas antes de por que é e por que nem sempre gostaria de usar isso o tempo todo, mas se você ler a documentação para as aulas, verá muitos métodos de classe que agem dessa maneira e eles são frequentemente usados.

Para NSString, você tem, por exemplo:

+ (id)string  // (Empty string)
+ (id)stringWithFormat:...  // Formatted string (like you use)
+ (id)stringWithContentsOfURL:... // String populated with contents of URL

E assim por diante. E você então usaria isso como: NSString *myString = [NSString stringWithFormat:@"Hello %@\n", userName];

A maioria das outras classes tem isso, como nsarray:

+ (id)array
+ (id)arrayWithContentsOfFile:...
+ (id)arrayWithContentsOfURL:...
+ (id)arrayWithObjects:...

Você só precisa ler a documentação. :) E leia as outras respostas sobre por que você não quer usar muito isso.

aloc : A memória é alocada/dada à referência de objetos. Agora, a referência tem a posse da memória, mas ainda não fez nada. Essa memória está vazia (caso mais raro) ou com alguns dados anônimos.

aloc e init : A memória alocada é limpa/esvaziada. A memória é iniciada por bit zero.

aloc e initwithdata ... : A memória alocada é iniciada com dados desejados respeitados às propriedades da classe.

Por exemplo, quando você compra um enredo, obtém a posse. Este enredo é dado a você como é, tijolos em ruínas ou casa velha podem estar lá. Isto é aloc.

Ao limpar o enredo e remover toda a sujeira e ninhada. Isto é aloc com init.

Quando você construa isso em uma casa valiosa, torna -se mais significativo para você. E isso é Aloc initwith ...

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