web-dev-qa-db-fra.com

Un tableau [AnyObject] peut-il être facultativement descendu vers un tableau spécifique au type?

Je lis la documentation Swift, en consultant la section concernant la conversion de type.

La documentation parle de l'obtention d'un tableau de type [AnyObject] des trucs des frameworks Foundation (ce qui serait un NSArray * dans Objective-C).

Tout d'abord, la documentation fournit cet exemple:

for object in someObjects {
    let movie = object as Movie
    println("Movie: '\(movie.name)', dir. \(movie.director)")
}

Maintenant, je veux changer l'exemple légèrement, dans un cas où je ne sais pas que tous les objets sont de type Movie, donc je ferais ceci:

for object in someObject {
    if let movie = object as? Movie {
        println("Movie: '\(movie.name', dir. \(movie.director)")
    }
}

La documentation fournit ensuite un exemple d'une meilleure façon d'écrire la première boucle:

for movie in someObjects as [Movie] {
   println("Movie: '\(movie.name)', dir. \(movie.director)")
}

Où nous abattons someObjects à partir d'un [AnyObject] à un [Movie] donc nous n'avons pas à abattre dans la boucle.

Et cela m'a fait penser, le tableau peut-il être abaissé dans son ensemble?

if let someMovies = someObjects as? [Movie] {
    for movie in someMovies {
        println("Movie: '\(movie.name)', dir. \(movie.director)")
    }
}

Est-ce que ça marche? Et si oui, à quel point est-ce mauvais du point de vue des performances? Combien de temps faudrait-il pour vérifier le type de chaque objet dans un tableau de 10 000 éléments en utilisant le downcast optionnel?

Je comprends que les implications entre cet extrait de code et mon extrait de conversion downcast facultatif précédent sont différentes. Le premier parcourt chaque objet et n'essaie d'imprimer que si l'objet est un Movie, où le second n'entre dans la boucle que si le tableau peut être descendu en [Movie] array, auquel cas il imprimera tout ou rien, mais je peux imaginer qu'il y a des situations où cela serait préférable.

41
nhgrif

Vous l'avez - cela fonctionne exactement comme votre exemple de code:

let strings = ["Hi", "Hello", "Aloha"]
let anyObjects: [AnyObject] = strings

if let downcastStrings = anyObjects as? [String] {
    println("It's a [String]")
}
// console says "It's a [String]"

Aucune idée sur les performances, mais je ne suppose pas qu'il devra parcourir le tableau complet pour déterminer si un abaissement est possible.


Je suis donc devenu curieux et j'ai effectué un test rapide avec 100 000 valeurs simples dans un couple différent [AnyObject] configurations, où j'essaie de convertir le tableau en [String] vs la descente des éléments individuels:

// var anyObjects: [AnyObject] = [AnyObject]()
// filled with random assortment of Int, String, Double, Bool
Running test with mixed array
downcast array execution time = 0.000522
downcast elements execution time = 0.571749

// var actuallyStrings: [AnyObject] = [AnyObject]()
// filled with String values
Running test with all strings
downcast array execution time = 1.141267
downcast elements execution time = 0.853765

Il semble que ce soit super rapide de rejeter le tableau mixte comme non downcastable, car il suffit de scanner jusqu'à ce qu'il trouve un élément nonString. Pour un tableau qu'il peut downcast, il doit clairement traverser l'ensemble du tableau, et prend beaucoup plus de temps, bien que je ne sais pas pourquoi ce n'est pas la même vitesse que de parcourir le tableau et de vérifier manuellement chaque élément.

38
Nate Cook

Essayons ça

var someObjects = [
    NSString(),
    NSUUID()
]
let uuids = someObjects as? NSUUID[]

uuids est nul

var someOtherObjects = [
    NSUUID(),
    NSUUID()
]
let all_uuids = someOtherObjects as? NSUUID[]

all_uuids est égal à someOtherObjects

Il semble donc que cela fonctionne. Vous pouvez utiliser l'expression pour tester si tous les éléments du tableau sont du type attendu, mais il ne filtrera pas le tableau pour sélectionner uniquement le type attendu.

1
Rod