How Is a Return Value of Anyobject! Different from Anyobject

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 and AnyObject 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 ids 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 NSObjects.

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



Leave a reply



Submit