Given a Swift `Any` type can I determine if it's an `Optional`?
You can use runtime introspection using Mirror
:
let foo: String? = "foo"
let bar: String = "bar"
var a: Any = foo
// if wrapping an optional, the reflection of the value has
// a displaystyle "optional"
if let displayStyle = Mirror.init(reflecting: a).displayStyle {
print(displayStyle) // optional
}
// for a non-optional fundamental native type: no displaystyle
a = bar
if let displayStyle = Mirror.init(reflecting: a).displayStyle {
print(displayStyle)
} // prints nothing
Optional/non-optional example where the underlying type is user-defined (non native):
struct Foo {}
let foo: Foo? = Foo()
let bar: Foo = Foo()
var a: Any = foo
// if wrapping an optional, the reflection of the value has
// a displaystyle "optional"
if let displayStyle = Mirror(reflecting: a).displayStyle {
print(displayStyle) // optional
}
// for a non-optional non-fundamental type:
a = bar
if let displayStyle = Mirror(reflecting: a).displayStyle {
print(displayStyle) // struct
}
If you don't want need to use the binded displayStyle
variable (e.g. for printing) but simply want check whether the wrapped value is any kind of optional, you can add a boolean clause to the if
statement that holds the optional binding of the displayStyle
case,
if let displayStyle = Mirror(reflecting: a).displayStyle,
displayStyle == .optional {
// is an optional ...
}
... or remove the binding entirely in favour of a single conditional expression using the nil coalescing operator (??
)
if Mirror(reflecting: a).displayStyle ?? .class == .optional {
// is an optional
}
Note however that for all the methods above, this simply tells you as dev whether the type wrapped by the Any
instance is optional or not: Swifts typing system still knows nothing of the sort.
Determine if Any.Type is Optional
Assuming that what you are trying to do is something like this:
let anyType: Any.Type = Optional<String>.self
anyType is Optional<Any>.Type // false
Sadly swift currently (as of Swift 2) does not support covariance nor contravariance and type checks directly against Optional.Type
cannot be done:
// Argument for generic parameter 'Wrapped' could not be inferred
anyType is Optional.Type // Causes error
An alternative is to make Optional
extend an specific protocol, and check for that type:
protocol OptionalProtocol {}
extension Optional : OptionalProtocol {}
let anyType: Any.Type = Optional<String>.self
anyType is OptionalProtocol.Type // true
How can you check if a type is Optional in Swift?
This is a hacky but working solution:
func isOptional(_ type: Any.Type) -> Bool {
let typeName = String(describing: type)
return typeName.hasPrefix("Optional<")
}
Test:
let t1 = Int?.self
let t2 = Bool.self
print(isOptional(t1))
// true
print(isOptional(t2))
// false
Swift: Testing optionals for nil
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
Checking optional isEqualToString
Optional
has an ==
operator defined for it in the Swift standard library:
func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool
That means if the optional contains a value that’s equatable, you can compare two optionals. If the two optionals are both nil they’re equal, and if the two optionals wrap values that are equal, then they’re equal.
So if you don’t care about whether person.name
is nil
or not, just whether it contains a value of "John", you can just write if person.name == "John"
.
How does that work, when "John" is a String
not a String?
?* Because Swift will implicitly convert any type to an optional wrapping that type if that’s what an argument requires. So because the ==
function for comparing optionals requires a String?
argument, “John” will be implicitly converted to {Some "John"}
, allowing the ==
operator between two optionals to be used.
* well actually "John” isn't a String
either, it’s a string literal that is getting converted into a String
Related Topics
Adding Data to a Specific UId in Firebase
Wkwebview Problems in Macos Mojave
How to Resolve Rctpromiseresolveblock After Bftask
Issue with Optional Core Data Relationship Using Nspersistentcloudkitcontainer
Tapping Is Required Twice to Uncheck Table Cell
How to Get Data to Return from Nsurlsessiondatatask in Swift
Calculate Age with Textfield Swift 4
Mapping a Dictionary to an Array of Structs in Swift
Streaming .M3U8 Using Mpmovieplayercontroller Does Not Work
How to Drag a Working Slider Using Swiftui
Optional in Swift, Return Count of Array
Applescript Used in My Cocoa MAC App, Stopped Working in Osx 10.14
Access Environment Variable Inside Global Function - Swiftui + Coredata
Skipnext Skipprevious Google Cast Greyed Out
Qlpreviewcontroller Showing File Then Going Blank in Swiftui