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

我正在将我的 iOS 项目迁移到 Swift。我正在一节一节地上这门课。当我从 Swift 调用 Objective C 方法时,许多 Objective C 类型被转换为它们的 Swift 对应方法。

在我的情况下,一个目标 C NSMutableArray被转换为斯威夫特的 Array<AnyObject>。现在我的问题来了。在 Swift 类中,我从 Objective C 对象得到这样一个数组。既然我已经进入了 Swift 的世界,我想将这个数组强制转换为一个特定的类型,而不是 AnyObject,因为我确切地知道这个数组中存在哪种类型的对象。

编译器不让我这么做!让我简化一下我的问题: 我想强制转换为包含字符串的数组。这就是我试过的:

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

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

“ String”与“ AnyObject”不完全相同

我必须同意编译器的说法,因为 String 实际上与 AnyObject 不完全相同。但我不觉得这有什么问题。如果我愿意,我可以将 AnyObject 向下转换为 String,对吗?

我也试过:

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

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

‘ NSArray’不是‘ NSMutableArray’的子类型

有什么办法能达到我的目的吗?

77865 次浏览

你可以使用双向下拉,首先到 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]。相反,你应该使用带有条件向下转换 as?if let:

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]

使用 Swift 1.2,下面的代码可以工作:

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

在 Xcode 6.3中,我使用了以下代码:

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


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


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

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 }

快速3

你可以考虑下面的代码

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

在我的例子中,编译器希望我像这样编写它来抑制所有的警告和编译问题,所以不仅仅是感叹号,即使字段 images Field 已经用1声明,而且还要用括号和“ as!”确保没人抱怨。

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

这让我很不舒服... 斯威夫特可以更好,它的新语言,所以... 我扩展:

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

指定为 Array:

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])
}