in Swift: Difference between Array VS NSArray VS [AnyObject]
Array
is a struct, therefore it is a value type in Swift.NSArray
is an immutable Objective C class, therefore it is a reference type in Swift and it is bridged to Array<AnyObject>
.NSMutableArray
is the mutable subclass of NSArray
.
var arr : NSMutableArray = ["Pencil", "Eraser", "Notebook"]
var barr = ["Pencil", "Eraser", "Notebook"]
func foo (var a : Array<String>)
{
a[2] = "Pen"
}
func bar (a : NSMutableArray)
{
a[2] = "Pen"
}
foo(barr)
bar(arr)
println (arr)
println (barr)
Prints:
(
Pencil,
Eraser,
Pen
)
[Pencil, Eraser, Notebook]
Because foo
changes the local value of a
and bar
changes the reference.
It will also work if you do let arr
instead of var
as with other reference types.
[AnyObject] is not identical to NSArray
Found answer to both of my questions -
Since NSArray is immutable and [AnyObject] is Array type in Swift that's mutable, compiler complains they are not identical. I changed NSArray! to Array! in Swift code. Other option is was to change Objective-C code to
success:(void (^)(NSMutableArray *response))success
(not preferred as it kills the purpose of using the bridge).Cast the Array to NSMuatableArray before calling the block in Objective-C
Why is a Swift ArrayInt compatible with AnyObject?
If you import Foundation
(which you must be, because you reference NSCoder
) then [Int]
is implicitly bridged to NSArray
because Int
is implicitly bridged to NSNumber
. Int64
and your non-objc structs are not implicitly bridged to ObjC types, so arrays of those are not bridged to NSArray
.
Why casting function type as AnyObject works
Behind the scenes as AnyObject
converts the casted value to an Objective-C compatible one: Int
's become NSNumber
, array's become NSArray
, and so on. Swift-only values get wrapped within opaque SwiftValue
instances.
print(type(of: test2)) // __SwiftValue
This is why adding as AnyObject
makes your code compile, as the right-hand of the operator is now an object.
Swift why does as? require AnyObject vs Any
I guess this doesn't really answer the original question. However, it is a workaround that gets the job done. I still don't understand why the solution above doesn't work (especially the fatal error when casting from [AnyObject] to [Any]), but I took a different approach which works great:
extension NSArray {
public func toSwiftArray<Type>() -> [Type] {
var swiftArray = [Type]()
for value in self {
if let valueOfType = value as? Type {
swiftArray.append( valueOfType )
}
}
return swiftArray
}
public func toSwiftArray<Type>() -> ([Type], [Any]) {
var swiftTypeArray = [Type]()
var unknownTypeArray = [Any]()
for value in self {
if let valueOfType = value as? Type {
swiftTypeArray.append( valueOfType )
} else {
unknownTypeArray.append( value )
}
}
return (swiftTypeArray, unknownTypeArray)
}
}
Not sure why I couldn't use .filter to do this, but this is a very straightforward solution to the problem, and it also allows for a version that returns a list of the values that couldn't be converted. This is very handy routine for converting to NSArray with full type safety.
AnyObject and Any in Swift
AnyObject
is only for reference types (classes), Any
is for both value and reference types.
So you should go for [String: Any]
.
Type Casting for Any and AnyObject
Swift provides two special types for working with nonspecific types:
Any
can represent an instance of any type at all, including function
types.AnyObject
can represent an instance of any class type.
NOTE:
Use
Any
andAnyObject
only when you explicitly need the behavior and
capabilities they provide. It is always better to be specific about
the types you expect to work with in your code.
From The Swift Programming Language:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342
-
Also note that when you work with Cocoa API, it's common to receive an Array of AnyObject, this is because Objective-C arrays are NOT typified.
So you need to cast them to the array type you expect.
-
EDIT: (december 22, 2015)
On the last statement, note that this is changing with Swift 2.0 and Xcode 7.
Apple has introduced ‘Lightweight’ generics in Objective-C so lots of Cocoa APIs now already returns the correct type.
EDIT: (october 18, 2016)
Note that, as of Swift 3.0, Objective-C id
s are now imported as Any
, not anymore as AnyObject
.
How can this [AnyObject] return as AnyObject?
So why no any warning or error issue?
There would have been if you hadn't of said as AnyObject
:
class Brain {
var internalProgram = [AnyObject]()
var program: AnyObject {
get {
// compiler error:
// Return expression of type '[AnyObject]' does not conform to 'AnyObject'
return internalProgram
}
}
}
The compiler is telling us that [AnyObject]
doesn't conform to AnyObject
– which is perfectly true. A Swift Array
is a struct
, not a class
, therefore cannot directly be typed as an AnyObject
.
However, you then say as AnyObject
. By doing so, you're bridging the Swift Array
to NSArray
(when Foundation is imported) – which is a class
. Therefore it can be typed as an AnyObject
. You can see the full list of Foundation types which can be bridged to here.
Furthermore it's worth noting that in Swift 3, everything can be bridged to AnyObject
due to the introduction of the opaque _SwiftValue
type, which can wrap an arbitrary Swift value in an Obj-C compatible box (including Array
when Foundation isn't imported).
Because anything can now be an AnyObject
, it's pretty much as weak a type as Any
. On top of this, it also lets you call any known @objc
method on it, completely disregarding type safety and is almost guaranteed to cause you problems with _SwiftValue
boxing. For those reasons, you should avoid using AnyObject
wherever you can. There is nearly always a stronger type available for you to use.
Related Topics
How Does Google's Custom iOS Keyboard, Gboard, Programmatically Dismiss the Frontmost App
Don't Launch Simulator When Running Unittests
Could Not Find a Valid Googleservice-Info.Plist in Your Project
Set Background Color of Active Tab Bar Item in Swift
Corelocation Heading Base on Back Camera (Augmented Reality)
How to Draw a Line in Sprite-Kit
"'Cdvplugin.H' File Not Found" in Cordova as Component (Cleaver)
Open Target="_Blank" Links Outside of Uiwebview in Safari
iOS Unable to Find Plugins, Android Fine
Launch Images in iOS 7 with Xcode 5
How to Capture Picture with Avcapturesession in Swift
This Certificate Was Signed by an Unknown Authority
Get Selected Index of Uitableview
Upload Multiple Images in Swift Using Alamofire
Swift: Testing Optionals for Nil
Libmobilegestalt Mobilegestaltsupport.M:153 Mobilegestalt.C:550 Xcode Console
Is There Function to Convert Uicolor to Hue Saturation Brightness