Com o código a seguir, tento definir uma classe de modelo simples e seu inicializador failable, que leva um dicionário (json-) como parâmetro. O inicializador deve retornar nil
se o nome do usuário não estiver definido no json original.
1. Por que o código não compila? A mensagem de erro diz:
Todas as propriedades armazenadas de uma instância de classe devem ser inicializadas antes de retornar nil de um inicializador.
Isso não faz sentido. Por que devo inicializar essas propriedades quando pretendo retornar nil
?
2. Minha abordagem é a correta ou haveria outras idéias ou padrões comuns para atingir meu objetivo?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
swift
object-initializers
Kai Huppmann
fonte
fonte
canSetCalculableProperties
parâmetro booleano que permite ao meu inicializador calcular propriedades que podem ou não ser criadas instantaneamente. Por exemplo, se umadateCreated
chave estiver faltando e eu puder definir a propriedade imediatamente porque ocanSetCalculableProperties
parâmetro é verdadeiro, apenas defini-lo para a data atual.Respostas:
Atualização: Do Swift 2.2 Change Log (lançado em 21 de março de 2016):
Para Swift 2.1 e anterior:
De acordo com a documentação da Apple (e o erro do seu compilador), uma classe deve inicializar todas as suas propriedades armazenadas antes de retornar
nil
de um inicializador disponível:Nota: Na verdade, funciona bem para estruturas e enumerações, mas não para classes.
A maneira sugerida de lidar com propriedades armazenadas que não podem ser inicializadas antes que o inicializador falhe é declará-las como opcionais implicitamente desembrulhados.
Exemplo dos documentos:
No seu caso, entretanto, simplesmente definir
userName
como umString!
não corrige o erro de compilação porque você ainda precisa se preocupar em inicializar as propriedades em sua classe baseNSObject
,. Felizmente, comuserName
definido como aString!
, você pode realmente chamarsuper.init()
antes dereturn nil
que irá iniciar suaNSObject
classe base e corrigir o erro de compilação.fonte
Product
classe) não pode acionar uma falha de inicialização antes de atribuir um valor específico, embora a documentação diga que pode. Os documentos não estão sincronizados com a versão Swift mais recente. É aconselhável torná-lo umvar
por agoralet
. fonte: Chris Lattner .De acordo com Chris Lattner, isso é um bug. Aqui está o que ele diz:
Fonte
EDITAR:
Então o swift agora é de código aberto e de acordo com este changelog ele está corrigido agora em instantâneos do swift 2.2
fonte
Aceito que a resposta de Mike S seja uma recomendação da Apple, mas não acho que seja a melhor prática. O objetivo de um sistema de tipo forte é mover os erros de tempo de execução para o tempo de compilação. Essa "solução" anula esse propósito. IMHO, melhor seria ir em frente e inicializar o nome de usuário para
""
e, em seguida, verificá-lo após o super.init (). Se nomes de usuário em branco forem permitidos, defina um sinalizador.fonte
Outra maneira de contornar a limitação é trabalhar com funções de classe para fazer a inicialização. Você pode até querer mover essa função para uma extensão:
Usá-lo seria:
fonte
Embora o Swift 2.2 tenha sido lançado e você não precise mais inicializar totalmente o objeto antes de falhar no inicializador, você precisa segurar seus cavalos até que https://bugs.swift.org/browse/SR-704 seja corrigido.
fonte
Eu descobri que isso pode ser feito no Swift 1.2
Existem algumas condições:
Exemplo:
fonte
Trecho de: Apple Inc. “ The Swift Programming Language. ”IBooks. https://itun.es/sg/jEUH0.l
fonte
Você pode usar o init de conveniência :
fonte