如何将NSMutableArray强制转换为特定类型的Swift数组?


68

我正在将iOS项目迁移到Swift。我正在上课。当我从Swift调用Objective C方法时,很多Objective C类型都转换为它们的Swift对应类型。

在我的情况下,目标CNSMutableArray转换为Swift的Array<AnyObject>。现在是我的问题了。在我的Swift类中,我从Objective C对象获得了这样的数组。现在我处于Swift世界中,我想将此数组转换为特定类型而不是AnyObject,因为我确定知道该数组中存在哪种对象。

编译器不允许我这样做!让我通过说要转换为包含字符串的数组来简化我的问题。这是我尝试的:

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

我从编译器收到以下错误:

“字符串”与“ AnyObject”不同

我必须同意编译器,因为String确实与AnyObject不同。但是我不明白为什么这是一个问题。如果需要,我可以将AnyObject转换为String,对吗?

我也尝试过:

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

这似乎是朝着正确方向迈出的一步,但是getStrings()返回,NSMutableArray因此出现以下错误:

“ NSArray”不是“ NSMutableArray”的子类型

有什么办法可以做我想在这里做的事情吗?

Answers:


135

您可以先进行两次向下转换NSArray,然后再进行到[String]

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

在操场上进行了以下测试:

import Foundation

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

更新:

在更高版本的Swift(至少1.2版)中,编译器会抱怨as [String]。相反,您应该使用if let带有条件下调的as?

import Foundation

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

如果您绝对确定NSMutableArray可以将其强制转换为[String],则可以as!改用(但是在大多数情况下您可能不应该使用):

import Foundation

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

1
感谢您对我的问题的清晰准确的答复!现在可以使用!
Tom van Zummeren 2014年

我也用它来解决我的GestureRecognizers问题。var arrayOfGestureRecognizers: [UIGestureRecognizer] = self.topViewController.view.gestureRecognizers! as NSArray as [UIGestureRecognizer]谢谢!
约书亚舞

@Mike,可以用NSArray as! [String]Swift 1.2更新答案吗?
克里斯·康诺夫

1
我还想指出,在ObjC源代码中,您可以将必需的泛型类型添加到objc属性。在我看来,这比进行所有这些铸造要干净得多。
Oxcug

@theMonster尚不适用于NSMutableArray(仅适用于NSArray),以为我看到了Swift 3的讨论。–
Alexandre G

36

compactMap是您在Swift 4.1及更高版本以及Swift 3.3-3.4中的朋友。这意味着您没有任何重复或强制转换。

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

在Swift的早期版本(2.0-3.2和4.0)中,您将需要使用flatMap此功能。用法与compactMap

let swiftArray: [String] = mutableArray.flatMap { $0 as? String }

1
这样做的好处是,即使该数组不能转换为一个整体,因为一些包含的元素是不是类型String/ NSString,在“兼容”的元素仍然可以被打捞上岸。
Nicolas Miari '17

5

使用Swift 1.2,以下方法将起作用:

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

当我在Swift 1.2中尝试此操作时,我得到:'NSMutableArray'无法转换为'[AnyObject]'; 你是说用“ as!”吗?强迫垂头丧气?
Tom van Zummeren

5
let mutableArray = NSMutableArray()

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

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

2

在Xcode 6.3中,我使用了以下内容:

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

1

迅速3

您可以考虑以下代码

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

0

在我的情况下,编译器希望我这样写,以消除所有警告和编译问题,因此,即使已使用一个字段声明了imagesImageField,也不只是带有感叹号,还包括了括号和“ as!”。确保没有人抱怨。

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

这让我非常不舒服。Swift可能更好,它的新语言也是如此。。。我做了扩展:

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

分配给数组:

extension Array: CSLang {
}

现在,我可以像这样写同样的语句,并且效果相同:

[UIImage].cast(imagesField.images)

不管喜欢与否,这是我的方法,更少的疑问和感叹号,更好。我也做了单元测试:

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])
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.