Os parâmetros 'var' foram descontinuados e serão removidos no Swift 3

120

Tudo bem, então eu atualizo o Xcode para 7.3 e agora recebo este aviso:

Os parâmetros 'var' foram descontinuados e serão removidos no Swift 3

Como corrigir isso quando eu preciso usar o var nesta função:

public func getQuestionList(var language: String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}
SDW
fonte
6
Como sobrepublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro 22/03
2
Não, este não é um substituto adequado. O OP provavelmente não deseja getQuestionter efeitos colaterais.
usar o seguinte
5
Sinceramente, não tenho ideia de por que eles considerariam remover isso. Foi um dos recursos que tornou o Swift incrível!
Danny Bravo
Nunca usei eu mesmo e não entendo o barulho.
Mike Taverne
@MikeTaverne (resposta tardia) Considere a seguinte função: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Isso é impossível sem var params. Você precisa criar um var separado dentro da função e copiar o valor ou marcar o parâmetro como inout. O primeiro é lento, o segundo causa comportamento indefinido. Muitos algoritmos usam recursão como esta.
kevin

Respostas:

82

Você já tentou atribuir a um novo var

public func getQuestionList(language: String) -> NSArray {
    var lang = language
    if self.data.count > 0 {
        if (lang.isEmpty) {
            lang = "NL"
        }
        return self.data.objectForKey("questionList" + lang) as! NSArray
    }

    return NSArray()
}
garanda
fonte
11
Não realmente o que eu acho que o OP queria
enxofre
6
Eu teria entendido a pergunta do OP da mesma maneira que a @garana. O OP não usa inout na pergunta, apenas modifica localmente uma variável pré-existente .
22716 Eric Aya
11
Na verdade, esta é a solução correta. Por favor, veja a questão Swift evolução que propôs esta mudança: github.com/apple/swift-evolution/blob/master/proposals/...
Scott Thompson
8
@TimVermeulen Todo mundo quer usar um idioma progressivo. A Apple pode desenvolver seu idioma de várias maneiras, não alterando a sintaxe a cada mês. Como você sabe, vários trechos de documentos e códigos on-line expiraram ou estão desatualizados por causa da Apple. Os desenvolvedores precisam vir a este site para pedir ajuda com muitas perguntas estúpidas repetidamente por causa disso. A sintaxe deve ser sólida desde o início, se a Apple quiser que mais desenvolvedores sejam bons nisso.
TomSawyer
25
Use linguagem var = linguagem, se você não quer introduzir um outro nome de variável (que era a principal vantagem do parâmetro var em primeiro lugar imo)
Harris
102

A discussão sobre a remoção de Var de um parâmetro de função está totalmente documentada nesta submissão no GitHub: Remove Var Parameters

Nesse documento, você encontrará que as pessoas frequentemente confundem varparâmetros com inoutparâmetros. Um varparâmetro simplesmente significa que o parâmetro é mutável dentro do contexto da função, enquanto que com um inoutparâmetro o valor do parâmetro no ponto de retorno será copiado da função e para o contexto do chamador.

A maneira correta de resolver esse problema é remover vardo parâmetro e introduzir uma varvariável local . Na parte superior da rotina, copie o valor do parâmetro para essa variável.

Tr0yJ
fonte
44
Eu não entendo essa alteração, por que ter que escrever outra linha para criar uma var local mutável seria melhor do que apenas definir o parâmetro como uma var?
Ross Barbish 23/03
Para mim, essa mudança é boa porque está captando situações em que eu deveria ter implementado uma variável local, mas não o fiz porque tomei o caminho mais fácil e aceitei (antiga) a sugestão de Swift de tornar o parâmetro de entrada um var
dawid
1
Estou com @RossBarbish nisso. Então ... isso está sendo removido porque os desenvolvedores preguiçosos não conseguem distinguir entre parâmetros inout e var? Pfff ...
Danny Bravo
1
Isso parece muito desnecessário ..., eles deveriam ter mantido as duas opções.
Oscar Gomez
1
Provavelmente o swift estava declarando uma variável local acima do parâmetro nos bastidores, de qualquer maneira. Agora temos que fazer isso manualmente. Nenhuma mudança no desempenho, mas perdemos a conveniência de ajudar os iniciantes com um conceito simples.
Mogelbuster 5/05
62

Basta adicionar esta linha no início da função:

var language = language

e o restante do seu código pode permanecer inalterado, assim:

public func getQuestionList(language: String) -> NSArray {
    var language = language
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}
Harris
fonte
5
A melhor resposta de longe. Requer apenas uma alteração de linha.
usar o seguinte
Mas parece tão @ James não naturais
asyncwait
1
Eu sinto que esta é a melhor resposta, pois mantém o mesmo nome. Semelhante a como outros idiomas comuns fazem isso.
eonist 23/05
1
@RiverSatya Por que não usar o parâmetro diretamente?
Declan McKenna
1
Realmente uma sugestão incrível. Vamos implementá-lo desta forma, em Swiftify :)
Crulex
13

Muitas pessoas estão sugerindo um inoutparâmetro, mas não é para isso que elas foram projetadas. Além disso, não permite chamar a função com uma letconstante, nem com uma string literal. Por que você simplesmente não adiciona o valor padrão à assinatura da função?

public func getQuestionList(language language: String = "NL") -> NSArray {
    if data.count > 0 {
        return data.objectForKey("questionList" + language) as! NSArray
    } else {
        return NSArray()
    }
}

Apenas certifique-se de não chamar getQuestionListcom a string vazia caso queira o idioma padrão, mas deixe de fora o parâmetro:

let list = getQuestionList() // uses the default "NL" language
Tim Vermeulen
fonte
3
Eu também não entendo porque todo mundo saltou sobre a solução inout quando OP não estava mesmo usando que no começo ...
Eric Aya
1
Eles estavam assumindo que var e inout fizeram a mesma coisa.
ryantxr
2

Swift 4

public func getQuestionList(language: inout String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

getQuestionList(language: &someString)

Em alguns casos, como experimentei (com configurações mais complexas envolvendo matrizes), criar uma nova propriedade dentro do método e alterar essa propriedade nem sempre funciona. Sem mencionar, você está confundindo o método em vez de simplesmente anexar inoutum parâmetro e &seu argumento, para o qual essa sintaxe foi criada.

bsod
fonte
1
public func getQuestionList(language: inout String) -> NSArray {
if self.data.count > 0 {
    if (language.isEmpty) {
        language = "NL"
    }
    return self.data.objectForKey("questionList" + language) as! NSArray
}

return NSArray()

}

Abdul Rahman Khan
fonte
0

Acho que as respostas @Harris e @garanda são a melhor abordagem.

De qualquer forma, no seu caso, não há necessidade de um var, você pode fazer:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}
Simone Pistecchia
fonte
0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

Parâmetros de entrada e saída

Os parâmetros de função são constantes por padrão. Tentar alterar o valor de um parâmetro de função de dentro do corpo dessa função resulta em um erro em tempo de compilação. Isso significa que você não pode alterar o valor de um parâmetro por engano. Se você deseja que uma função modifique o valor de um parâmetro e deseja que essas alterações persistam após o término da chamada de função, defina esse parâmetro como um parâmetro de entrada e saída.

Você escreve um parâmetro in-out colocando a palavra-chave inout logo antes do tipo de um parâmetro. Um parâmetro de entrada e saída possui um valor que é passado para a função, é modificado pela função e é retornado para fora da função para substituir o valor original. Para obter uma discussão detalhada sobre o comportamento dos parâmetros de entrada e otimizações do compilador associadas, consulte Parâmetros de entrada.

Você só pode passar uma variável como argumento para um parâmetro in-out. Você não pode passar um valor constante ou literal como argumento, porque constantes e literais não podem ser modificados. Você coloca um e comercial (&) diretamente antes do nome de uma variável ao passá-lo como argumento para um parâmetro in-out, para indicar que ele pode ser modificado pela função.

NOTA

Parâmetros de entrada e saída não podem ter valores padrão e parâmetros variáveis ​​não podem ser marcados como entrada.

Aqui está um exemplo de uma função chamada swapTwoInts ( : :), que possui dois parâmetros inteiros de entrada e saída chamados aeb:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

A função swapTwoInts ( : :) simplesmente troca o valor de b em a e o valor de a em b. A função executa essa troca armazenando o valor de a em uma constante temporária chamada temporaryA, atribuindo o valor de b a a e depois atribuindo temporaryA a b.

Você pode chamar a função swapTwoInts ( : :) com duas variáveis ​​do tipo Int para trocar seus valores. Observe que os nomes de someInt e anotherInt são prefixados com um e comercial quando são passados ​​para a função swapTwoInts ( : :):

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

O exemplo acima mostra que os valores originais de someInt e anotherInt são modificados pela função swapTwoInts ( : :), mesmo que tenham sido originalmente definidos fora da função.

NOTA

Parâmetros de entrada e saída não são iguais a retornar um valor de uma função. O exemplo swapTwoInts acima não define um tipo de retorno ou retorna um valor, mas ainda modifica os valores de someInt e anotherInt. Os parâmetros de entrada e saída são uma maneira alternativa de uma função ter um efeito fora do escopo de seu corpo.

Mustafa Mohammed
fonte
0

Aqui está outra ideia. Meu caso de uso era passar um array de strings para anexá-lo, para o qual o array deve ser passado mutuamente. Também não queria ter estado na minha classe para isso. Então, eu fiz uma classe que contém a matriz e passa nela. Dependendo do seu caso de uso, pode parecer bobagem ter uma classe que contém apenas essa variável.

private class StringBuilder {
    var buffer: [String] = []

    func append(_ str: String) {
        buffer.append(str)
    }

    func toString() -> String {
        return buffer.joined()
    }
}

Eu só uso métodos appende joinedna matriz, por isso foi fácil alterar o tipo com outras alterações mínimas no meu código.

Alguns exemplos de uso:

private func writeMap(map: LevelMap, url: URL) -> Bool {
    let buffer = StringBuilder()

    if !writeHeader(map: map, buffer: buffer) {
        return false
    }
    if !writeFloors(map: map, buffer: buffer) {
        return false
    }

    let content = buffer.toString()
    do {
        try content.write(to: url, atomically: true, encoding: .utf8)
        return true
    } catch {}
    return false
}

private func writeHeader(map: LevelMap, buffer: StringBuilder) -> Bool {
    buffer.append("something here ...\n")
    return true
}
webjprgm
fonte
Minha resposta é se você deseja modificar o valor original, visto pelo chamador. Se você apenas deseja reatribuir localmente o valor, mas não afetar o chamador, outras respostas acima tratam disso.
Webjprgm