I am migrating my iOS project to Swift. I am doing this class by class. When I call Objective C methods from Swift, a lot of Objective C types are converted to their Swift counterparts.
In my case an Objective C NSMutableArray
gets converted to Swift's Array<AnyObject>
. Now here comes my problem. Within my Swift class, I get such an array back from an Objective C object. Now that I am in the Swift world, I would like to cast this array to a specific type instead of AnyObject
, because I know for sure what kind of objects exist in this array.
The compiler won't let me do that! Let me simplify my problem by saying I want to cast to an array containing strings. This is what I tried:
var strings = myObjcObject.getStrings() as [String]
I get the following error from the compiler:
'String' is not identical to 'AnyObject'
I would have to agree with the compiler, since String is indeed not identical to AnyObject. But I don't see why that is a problem. I can downcast AnyObject to String if I want, right?
I also tried:
var strings = myObjcObject.getStrings() as? [String]
This seems to be a step in the right direction, but getStrings() returns an NSMutableArray
so I get the following error:
'NSArray' is not a subtype of 'NSMutableArray'
Is there any way to do what I am trying to do here?
You can make this work with a double downcast, first to NSArray
, then to [String]
:
var strings = myObjcObject.getStrings() as NSArray as [String]
Tested in a Playground with:
import Foundation
var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as [String]
Update:
In later versions of Swift (at least 1.2), the compiler will complain about as [String]
. Instead you should use an if let
with a conditional downcast as?
:
import Foundation
var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
if let swiftArray = objCMutableArray as NSArray as? [String] {
// Use swiftArray here
}
If you are absolutely sure that your NSMutableArray
can be cast to [String]
, then you can use as!
instead (but you probably shouldn't use this in most cases):
import Foundation
var objCMutableArray = NSMutableArray(array: ["a", "b", "c"])
var swiftArray = objCMutableArray as NSArray as! [String]
compactMap
is your friend in Swift 4.1 and above, as well as in Swift 3.3-3.4 for that matter. This means that you don't have any double or forced casting.
let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray: [String] = mutableArray.compactMap { $0 as? String }
In previous versions of Swift, 2.0-3.2 and 4.0, you'll want to use flatMap
for this purpose. The usage is the same as compactMap
:
let swiftArray: [String] = mutableArray.flatMap { $0 as? String }
With Swift 1.2 the following will work:
let mutableArray = NSMutableArray(array: ["a", "b", "c"])
let swiftArray = NSArray(array: mutableArray) 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"]
}
in Xcode 6.3 i used the following:
var mutableArray = NSMutableArray(array:"1", "2", "3")
let swiftArray = mutableArray as AnyObject as! [String]
for swift 3
you may consider the following code
let array: [String] = nsMutableArrayObject.copy() as! [String]
In my case compiler wanted me to write it like this to suppress all warnings and compilation problems, so not just that exclamation marks even if field imagesField is already declared with one, but also parentheses and "as!" to make it sure that nobody complains.
(imagesField!.images as! [UIImage]) 🤮
It made me quite uncomfortable... Swift could be nicer, its new language so... I made extension:
public static func cast(_ object: Any) -> Self {
return object as! Self
}
Assigned it to Array:
extension Array: CSLang {
}
And now I can write the same statement like this with the same effect:
[UIImage].cast(imagesField.images)
Like it or not, this is my way, less question and exclamation marks, better. I made also unit test:
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])
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.