How is a return value of AnyObject! different from AnyObject
TLDR: Treat Foo!
as if it were Foo
.
Many Cocoa calls include implicitly unwrapped optionals, and their need for it is very likely the reason the feature even exists. Here's how I recommend thinking about it.
First, let's think about a simpler case that doesn't involve AnyObject
. I think UIDevice
makes a good example.
class func currentDevice() -> UIDevice!
What's going on here? Well, there is always a currentDevice
. If this returned nil
that would indicate some kind of deep error in the system. So if we were building this interface in Swift, this would likely just return UIDevice
and be done with it. But we need to bridge to Objective-C, which returns UIDevice*
. Now that should never be nil
, but it syntactically could be nil
. Now in ObjC, we typically ignore that fact and don't nil
-check here (particularly because nil
-messaging is typically safe).
So how would we express this situation in Swift? Well, technically it's an Optional<UIDevice>
, and you'd wind up with:
class func currentDevice() -> UIDevice?
And you'd need to explicitly unwrap that every time you used it (ideally with an if let
block). That would very quickly drive you insane, and for nothing. currentDevice()
always returns a value. The Optional
is an artifact of bridging to ObjC.
So they invented a hack to work around that (and I think it really is a hack; I can't imagine building this feature if ObjC weren't in the mix). That hack says, yes, it's an Optional
, but you can pretend it's not, and we promise it's always going to be a value.
And that's !
. For this kind of stuff, you basically ignore the !
and pretend that it's handing you back a UIDevice
and roll along. If they lied to you and return nil
, well, that's going to crash. They shouldn't have lied to you.
This suggests a rule: don't use !
unless you really need to (and you pretty much only need to when bridging to ObjC).
In your specific example, this works in both directions:
func valueForAttribute(key: String!) -> AnyObject!
Technically it takes an Optional<String>
, but only because it's bridged to NSString*
. You must pass non-nil
here. And it technically returns you Optional<AnyObject>
, but only because it's bridged to id
. It promises that it won't be nil
.
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.
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.
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 to Compare AnyObject Is Null or not?
Most likely you are looking to compare value
with NSNull
.
You can update your code as follows:
private func checkDataForValue(data: Any?) -> String {
if let value = data {
if value is NSNull != nil {
return "-"
} else if (value as? String)?.lowercased() == "<null>" {
return "-"
} else {
return "\(value)"
}
} else {
return "-"
}
}
What is difference between [NSObject: AnyObject] and AnyObject in swift
[NSObject: AnyObject]
is a dictionary that allows you to access one object by providing a different object. Simply putting AnyObject
means that your program doesn't know whether the parameter is a dictionary, a string, and int, or what, and therefore doesn't know how to handle it. Besides, the OS calls that method so you know you are getting a [NSObject: AnyObject]
every time, so why not have the parameter type that.
When is a variable a AnyObject but not a NSObject
On platforms with Objective-C compatibility (which means all of Apple's platforms and no others), every class type is (secretly) a subclass of the SwiftObject
class, which provides NSObject
protocol conformance.
On other platforms, NSObject
is “just another class”, implemented in Swift, so only a class that explicitly has NSObject
as a superclass has instances that are NSObject
s.
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.
what is the difference protocol's `: AnyObject` between `none`?
AnyObject
requires that conforming types be classes, rather than structs or enums. See Class-Only Protocols for details.
Classes provide reference semantics, rather than value semantics, which you may require for your protocol. For example, if you want to observe an object, that only makes sense for a reference type (you can't observe changes to a value type, since value types are copied when modified). For more details on that see Structures and Classes, and particularly the sections explaining value and reference types.
There is no value type equivalent of AnyObject
. You can't require value semantics for a protocol. This can lead to some headaches. As an example of the difference, consider the following:
protocol Incrementing {
var value: Int { get set }
}
extension Incrementing {
func incremented() -> Self {
var new = self // Value types copy, reference types reference
new.value += 1
return new
}
}
struct S: Incrementing { var value: Int = 0 }
class C: Incrementing { var value: Int = 0 }
var s = S()
s.incremented().value // 1
s.value // 0
var c = C()
c.incremented().value // 1
c.value // 1 (!!!)
This code makes sense for a struct, but is buggy for a class. There's no real fix for that in Swift today.
Related Topics
Fbsdkapplicationdelegate Application Openurl:Sourceapplication:Annotation Deprecated
Core Data: Could Not Cast Value of Type 'Mytype_Mytype_2' to Mytype
How to Add a Watermark to an Image Using This Code
Swift - How to Create a View with a Shape Cropped in It
Find Item of Specific Type in Array
Cannot Read the Nfc Chip of the Epassport Using iOS13
Getting Results from Arbitrary SQL Statements with Correct Binding in SQLite.Swift
How to Make Nsattributedstring Codable Compliant
How to Benchmark Swift Code Execution
Use of Undeclared Type 'Viewcontroller' When Unit Testing My Own Viewcontroller in Swift
Watchos3 Complication That Launches App
Is There Any Way of Locking an Object in Swift Like in C#
How to Use Storyboards with Spritekit Using Swift
What Is an Example of Drawing Custom Nodes with Vertices in Swift Scenekit