wake-up-neo.com

Wie kann ich ein NSMutableArray in ein Swift-Array eines bestimmten Typs umwandeln?

Ich migriere mein iOS-Projekt zu Swift. Ich mache diese Klasse für Klasse. Wenn ich Objective C-Methoden von Swift aus anrufe, werden viele Objective-C-Typen in ihre Swift-Pendants konvertiert.

In meinem Fall wird eine Ziel-Variable NSMutableArray in Swift's Array<AnyObject> konvertiert. Nun kommt mein Problem. In meiner Swift-Klasse bekomme ich ein solches Array von einem Objective-C-Objekt zurück. Jetzt, wo ich mich in der Welt von Swift befinde, möchte ich dieses Array anstelle von AnyObject in einen bestimmten Typ umwandeln, da ich sicher bin, welche Art von Objekten in diesem Array vorhanden sind.

Der Compiler lässt mich das nicht! Lassen Sie mich mein Problem vereinfachen, indem ich sage, dass ich ein Array mit Strings verwenden möchte. Das habe ich versucht:

var strings = myObjcObject.getStrings() as [String]

Ich erhalte folgende Fehlermeldung vom Compiler:

'String' ist nicht identisch mit 'AnyObject'

Ich müsste dem Compiler zustimmen, da String in der Tat nicht mit AnyObject identisch ist. Aber ich sehe nicht, warum das ein Problem ist. Ich kann AnyObject zu String downcastcast, wenn ich möchte, oder?

Ich habe auch versucht:

var strings = myObjcObject.getStrings() as? [String]

Dies scheint ein Schritt in die richtige Richtung zu sein, aber getStrings () gibt eine NSMutableArray zurück, daher bekomme ich die folgende Fehlermeldung:

'NSArray' ist kein Subtyp von 'NSMutableArray'

Gibt es eine Möglichkeit, das zu tun, was ich hier versuche?

58

Sie können dies mit einem doppelten Downcast durchführen, zuerst nach NSArray, dann nach [String]:

var strings = myObjcObject.getStrings() as NSArray as [String]

Getestet auf einem Spielplatz mit:

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as [String]

Update:

In späteren Versionen von Swift (mindestens 1.2) wird der Compiler sich as [String] beschweren. Verwenden Sie stattdessen einen if let mit einem bedingten Downcast as?:

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
if let swiftArray = objCMutableArray as NSArray as? [String] {
    // Use swiftArray here
}

Wenn Sie absolut sicher sind, dass Ihre NSMutableArray in [String] umgewandelt werden kann, können Sie stattdessen as! verwenden (in den meisten Fällen sollten Sie dies jedoch wahrscheinlich nicht verwenden):

import Foundation

var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as! [String]
124
Mike S

compactMap ist dein Freund in Swift 4.1 und höher sowie in Swift 3.3-3.4. Dies bedeutet, dass Sie kein Doppel- oder Zwangsgießen haben.

let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray: [String] = mutableArray.compactMap { $0 as? String }

In früheren Versionen von Swift, 2.0-3.2 und 4.0 sollten Sie flatMap für diesen Zweck verwenden. Die Verwendung ist die gleiche wie bei compactMap:

let swiftArray: [String] = mutableArray.flatMap { $0 as? String }
28
Simon Rice
let mutableArray = NSMutableArray()

mutableArray.add("Abc")
mutableArray.add("def")
mutableArray.add("ghi")

if let array = mutableArray as? [String] {
    print(array)    // ["Abc", "def", "ghi"]
}
5
Leo Dabus

Mit Swift 1.2 wird Folgendes funktionieren:

let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray = NSArray(array: mutableArray) as? [String]
5
average Joe

in Xcode 6.3 habe ich folgendes verwendet:

var mutableArray = NSMutableArray(array:"1", "2", "3")
let swiftArray = mutableArray as AnyObject as! [String]
2
Nazariy Vlizlo

für Swift 3

sie können den folgenden Code berücksichtigen 

let array: [String] = nsMutableArrayObject.copy() as! [String]
1
Amr Angry

Ich habe dafür eine Erweiterung für NSArray erstellt.

extension NSArray {
    func swiftArray<T>() -> [T] {
        let result: [T] = self.compactMap { $0 as? T }
        return result
    }
}

class Test {
    var title: String
    init(title: String) {
        self.title = title
    }
}

let mutableArray = NSMutableArray()
mutableArray.add(Test(title: "1"))
mutableArray.add(Test(title: "2"))
mutableArray.add(Test(title: "3"))
mutableArray.add(Test(title: "4"))

let tests: [Test] = mutableArray.swiftArray()
0
P5ycH0

In meinem Fall wollte der Compiler, dass ich es so schreibe, um alle Warnungen und Kompilierungsprobleme zu unterdrücken, nicht nur das Ausrufezeichen, auch wenn das Feld imagesField bereits mit einem deklariert ist, sondern auch Klammern und "as!" um sicher zu gehen, dass sich niemand beschwert.

(imagesField!.images as! [UIImage]) ????

Es hat mich ziemlich unbequem gemacht ... Swift könnte schöner sein, seine neue Sprache also ... Ich habe Erweiterung gemacht:

 public static func cast(_ object: Any) -> Self {
        return object as! Self
    }

Hat es Array zugewiesen:

extension Array: CSLang {
}

Und jetzt kann ich dieselbe Aussage mit dem gleichen Effekt wie folgt schreiben:

[UIImage].cast(imagesField.images)

Ob es mir gefällt oder nicht, das ist mein Weg, weniger Fragezeichen und Ausrufezeichen, besser. Ich habe auch Unit-Test gemacht:

func testCast() {
    let array: NSMutableArray? = NSMutableArray()
    array?.add("test string 1")
    array?.add("test string 2")
    let stringArray: [String] = [String].cast(array)
    XCTAssertEqual("test string 2", stringArray[1])
}
0
Renetik