web-dev-qa-db-fra.com

Swift/iOS: Comment utiliser les paramètres d'inout dans des fonctions avec AnyObject/Any ou Pointeurs

J'essaie d'écrire une fonction qui prend un pointeur de variable et un descripteur/clé et définit une nouvelle valeur pour la variable. Idéalement, le pointeur devrait être un objet ou une primitive, mais je pourrais aussi vivre avec des fonctions séparées (ou un paramètre supplémentaire). Dans mon code, je récupère la nouvelle valeur d'une base de données en utilisant également la clé, mais dans l'exemple suivant, je l'ai simplifiée avec des valeurs factices afin de pouvoir l'utiliser facilement dans un terrain de jeu:

import UIKit

func setValue(inout object: AnyObject, key: String) {
    switch key {
    case "String":
        object = "A String"
    case "UIColor":
        object = UIColor.whiteColor()
    case "Bool":
        object = true
    default:
        println("Unhandled key: \(key)")
    }
}

var string: String = "Default String"
var color: UIColor = UIColor.blackColor()
var bool: Bool = false

setValue(&string, "String")
setValue(&color, "UIColor")
setValue(&bool, "Bool")

Je reçois l'erreur suivante:

"Impossible d'appeler 'setValue' avec une liste d'arguments de type '(inout String, key String)'"

Je comprends que je mélange des objets et des primitifs ici. J'ai aussi essayé de le décomposer et de le séparer en deux fonctions, mais même cela échoue:

func setValue(inout object: AnyObject, key: String) {
    switch key {
    case "UIColor":
        object = UIColor.whiteColor()
    default:
        println("Unhandled key: \(key)")
    }
}

var color: UIColor = UIColor.blackColor()
setValue(&color, "UIColor")

Cela donne aussi la même erreur:

"Impossible d'appeler 'setValue' avec une liste d'arguments de type '(inout UIColor, key String)'"

Si je modifie 'AnyObject' en 'UIColor', cela fonctionne, mais le but de la fonction est qu'il accepte n'importe quel type de variable ou au moins tout type d'objet un autre paramètre)

Dans Objective-C, j'utilisais des pointeurs, mais le transfert de l'approche vers Swift ne fonctionnait pas non plus, résultat identique:

func setValue(object: UnsafeMutablePointer<AnyObject>, key: String) {
    switch key {
    case "String":
        object.memory = "A String"
    case "UIColor":
        object.memory = UIColor.whiteColor()
    case "Bool":
        object.memory = true
    default:
        println("Unhandled key: \(key)")
    }
}

Quelqu'un a-t-il une idée de ce qui me manque ici? Toute aide est très appréciée!

Merci!

9
Django

Mieux, vous pouvez créer une méthode générique comme ci-dessous:

func setValue<T>(inout object:T, key: String) {
    switch key {
    case "String":
        object = ("A String" as? T)!
    case "UIColor":
        object = (UIColor.whiteColor() as? T)!
    case "Bool":
        object = (true as? T)!
    default:
        println("Unhandled key: \(key)")
    }
}

Et appeler sera comme ça:

setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")

J'espère que ça aide!

9
Sohil R. Memon

Pour ce faire, utilisez la surcharge et laissez le compilateur choisir le bit de code approprié au moment de la compilation, au lieu de désactiver une chaîne au moment de l'exécution:

func setValue(inout object: String) {
    object = "A String"
}

func setValue(inout object: UIColor) {
    object = UIColor.whiteColor()
}

func setValue(inout object: Bool) {
    object = true
}

func setValue(inout object: Any) {
    println("Unhandled key: \(key)")
}

Cette approche ne fonctionnerait pas si vous avez une Any et que vous voulez indiquer à la fonction quel type est contenu dans la Any… mais dans ce cas, la raison pour laquelle vous avez des problèmes est que le compilateur fait sait ce que les types sont, alors vous pouvez en profiter.

7
Airspeed Velocity

Support de protocole pour inout

Lorsque vous convertissez une classe en protocole, vous vous retrouvez avec une référence immuable, qui ne peut pas être utilisée dans les paramètres de la fonction inout. Afin que vous puissiez:

  1. Utiliser la surcharge de méthode (ce qui peut dupliquer votre code et le rendre plus difficile à lire de manière congénitale, même si vous le refacturez)
  2. Ne pas utiliser inout (c'est ce que vous devriez faire)
  3. Ou vous pouvez faire ceci:

-

protocol IPositional{
    func setPosition(position:CGPoint)
}
extension IPositional{
    var positional:IPositional {get{return self as IPositional}set{}}
}
class A:IPositional{
    var position:CGPoint = CGPoint()
    func setPosition(position:CGPoint){
        self.position = position
    }
}
func test(inout positional:IPositional){
    positional.setPosition(CGPointMake(10,10))
}
var a = A()
test(&a.positional)
a.position//output: (10.0, 10.0)

Conclusion:
L’avantage de le faire de cette façon: c’est que vous pouvez maintenant avoir une "méthode inout" pour toutes les classes qui implémentent IPositional. Je recommande toutefois d’utiliser l’option 2. (Ne pas utiliser inout)

0
eonist

Le type d'objet doit correspondre au type de paramètre, y compris AnyObject:

func setValue(inout object: AnyObject, key: String) {
    switch key {
    case "String":
        object = "A String"
    case "UIColor":
        object = UIColor.whiteColor()
    case "Bool":
        object = true
    default:
        print("Unhandled key: \(key)")
    }
}

var string: AnyObject = "Default String"
var color: AnyObject = UIColor.blackColor()
var bool: AnyObject = false

setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")
0
fujianjin6471

-Utilisez Any au lieu de AnyObject pour couvrir les types de valeur et les structures.

-Vous devrez peut-être transtyper sur Any avant d'appeler votre méthode.

Exemple:

func swapAny( inout obj1: Any, inout obj2: Any )
{
    let temp = obj1
    obj1 = obj2
    obj2 = temp
}

utilisation:

var fooString: Any = "Foo"
var barString: Any = "Bar"

swapAny(&fooString, obj2: &barString)
println(fooString)//prints "Bar"
0
Gregzo