Reputation: 1502
I have written an NSURL extension in Swift.
extension NSURL {
var isDir : Bool {
do {
var isDir : AnyObject?
try self.getResourceValue(&isDir, forKey: NSURLIsDirectoryKey)
if let result = isDir?.boolValue {
return result
} else {
return false
}
} catch {
return false
}
}
}
That works. But I find some people "cast" the pointer (isDIR
in this case) to NSNumber
first. Examples are:
I've found no documentation says AnyObject
conforms to the BooleanType
protocol. So how does my code in Swift work?
Upvotes: 1
Views: 426
Reputation: 22385
Adding on to vacawama's answer, the Swift documentation is worded in a slightly confusing way. It says that for AnyObject
@objc
symbols are available as implicitly unwrapped optional methods and properties, respectively.
You might think this means everything is implicitly unwrapped, but that's not true. The methods are available as implicitly unwrapped optionals, but the properties types are all available as optionals. So while it is in generally unsafe to call a method on an AnyObject
, it is safe to access a property.
For example,
let str = "Hello!" as NSString
let any = str as AnyObject
str.firstObject // compiler error, firstObject is an NSArray property
any.firstObject // nil
This is why you can safely call boolValue
. It gets imported from NSNumber
and its type is changed to Bool?
.
Upvotes: 0
Reputation: 421
The documentation for getResourceValue(_ *value*:forKey:)
indicates that _ *value*:
is an AutoreleasingUnsafeMutablePointer<AnyObject?>
type, which means it is fundamentally a void pointer which can be cast to any type so long as it is a proper type. Therefore, the direct cast of isDir
to a Bool
will work because that is basically what it is, a Boolean type:
let boolResult: Bool = isDir as! Bool
simply works as a direct cast because it is a void type to begin with.
Upvotes: 1
Reputation: 154731
Command-click on AnyObject
and you will find the answer:
/// The protocol to which all classes implicitly conform.
///
/// When used as a concrete type, all known `@objc` methods and
/// properties are available, as implicitly-unwrapped-optional methods
/// and properties respectively, on each instance of `AnyObject`. For
/// example:
///
/// class C {
/// @objc func getCValue() -> Int { return 42 }
/// }
///
/// // If x has a method @objc getValue()->Int, call it and
/// // return the result. Otherwise, return nil.
/// func getCValue1(x: AnyObject) -> Int? {
/// if let f: ()->Int = x.getCValue { // <===
/// return f()
/// }
/// return nil
/// }
///
/// // A more idiomatic implementation using "optional chaining"
/// func getCValue2(x: AnyObject) -> Int? {
/// return x.getCValue?() // <===
/// }
///
/// // An implementation that assumes the required method is present
/// func getCValue3(x: AnyObject) -> Int { // <===
/// return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
/// }
///
/// - SeeAlso: `AnyClass`
@objc public protocol AnyObject {
}
So, you can call any @objc method on an AnyObject
instance.
If you type
let a: AnyObject?
in a Playground and then:
a?.
autocomplete will show you the complete list of methods you can call. And it is huge.
Upvotes: 2