【问题标题】:How can I cast an NSMutableArray to a Swift array of a specific type?如何将 NSMutableArray 转换为特定类型的 Swift 数组?
【发布时间】:2014-11-08 08:37:37
【问题描述】:

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

在我的例子中,Objective C NSMutableArray 被转换为 Swift 的 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' 的子类型

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

【问题讨论】:

    标签: ios objective-c swift


    【解决方案1】:

    您可以通过双重向下转换来完成这项工作,首先是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]
    

    【讨论】:

    • 感谢您对我的问题的清晰准确的回答!现在可以了!
    • 我也用它来解决我的 GestureRecognizers 问题。 var arrayOfGestureRecognizers: [UIGestureRecognizer] = self.topViewController.view.gestureRecognizers! as NSArray as [UIGestureRecognizer]谢谢!
    • @Mike,你能用NSArray as! [String] 更新你对 Swift 1.2 的回答吗?
    • 我还要注意的是,在 ObjC 源代码中,您可以将必要的泛型类型添加到 objc 属性中。在我看来,这比做所有这些演员要干净得多。
    • @theMonster 还不适用于 NSMutableArray(仅适用于 NSArray),我想我看到了关于 Swift 3 的讨论..
    【解决方案2】:

    在 Swift 1.2 中,以下内容将起作用:

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

    【讨论】:

    • 当我用 Swift 1.2 尝试这个时,我得到:'NSMutableArray' 不能转换为 '[AnyObject]';你的意思是用'as!'强制沮丧?
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:
      let mutableArray = NSMutableArray()
      
      mutableArray.add("Abc")
      mutableArray.add("def")
      mutableArray.add("ghi")
      
      if let array = mutableArray as? [String] {
          print(array)    // ["Abc", "def", "ghi"]
      }
      

      【讨论】:

        【解决方案5】:

        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 }
        

        【讨论】:

        • 这样做的好处是,即使数组不能作为一个整体进行强制转换,因为它包含的一些元素是不是String/NSString 类型的,“兼容”元素仍然可以挽救。
        【解决方案6】:

        对于 Swift 3

        你可以考虑下面的代码

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

        【讨论】:

          【解决方案7】:

          在我的例子中,编译器希望我这样写,以抑制所有警告和编译问题,所以即使字段 imagesField 已经声明为一个,也不只是感叹号,还有括号和“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])
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-06-06
            • 2017-06-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多