23

I'm working with the Mirror in swift, I found Mirror.Child is very strange, the label is nullable, but the value seems not nullable.

public typealias Child = (label: String?, value: Any)

I don't know how to check if the value is nil or not.

let b: Bool? = true
let a: Any = b
print(a == nil) // false

I have one solution:

print(String(describing: a) == "nil") // true

but it is obviously not a good solution.

what is the best way to check if a is nil or not ?

Let me put more detail,

let mirror = Mirror(reflecting: object) // object can be any object.
for child in mirror.children {
    guard let label = child.label else {
        continue
    }
    // how to check if the value is nil or not here ?
    setValue(child.value, forKey: label)
}
JIE WANG
  • 1,875
  • 1
  • 17
  • 27
  • Is there a reason you don't just check that `b` is true or false? – Jake May 09 '18 at 13:31
  • @Jake as I said, the real code is about `Mirror`, I can't have the `b` directly in the real code. – JIE WANG May 09 '18 at 13:34
  • `guard let testValue = b else { return }` – Jake May 09 '18 at 13:34
  • With `let b: Bool? = true` if you use `let a: Any = b` compiler will show warning to add a default value. Rather you can use option value of any as `let a: Any? = b` and can check as `if a == nil { }` – Ankit Jayaswal May 09 '18 at 13:36
  • @AnkitJayaswal, that's not what I want. – JIE WANG May 09 '18 at 13:40
  • I don't don't know if `Mirror` works but looking into your updated qustion, you can check it with `label` as `guard let label = child.label, let value = child.value else { continue }` and use it as `setValue(value, forKey: label) ` – Ankit Jayaswal May 09 '18 at 13:44
  • 1
    I have yet to find a situation where `Mirror` is the tool you want. If you're trying to create a reflection system, you will find that `Mirror` is inadequate to the problem. It is not currently possible to build a reflection system in Swift (which is why Codable had to have special compiler support; it's not possible to write it in Swift). – Rob Napier May 09 '18 at 13:46
  • 1
    I'm also confused by your use of `setValue(_:forKey:)`. That's part of the ObjC runtime, unless you have your own version of it. `Mirror` and the ObjC runtime are not particularly compatible. If you want to do refection only of NSObject-subclasses, that has extensive support through the ObjC runtime. – Rob Napier May 09 '18 at 13:47
  • @RobNapier It's `NSManagedObject` – JIE WANG May 09 '18 at 13:48
  • @AnkitJayaswal this doesn't work `Initializer for conditional binding must have Optional type, not 'Any'` . the `label` is not optional. – JIE WANG May 09 '18 at 13:49
  • 1
    You don't want `Mirror`. You want to dig into the ObjC runtime. For example, `class_getProperty`, `class_getInstanceMethod`, etc. – Rob Napier May 09 '18 at 13:51
  • why not mirror? it works fine. – JIE WANG May 09 '18 at 13:53
  • 1
    Actually, I take that back. If this is `NSManagedObject`, it's easier than that. Look at `NSManagedObjectModel` and particularly `NSEntityDescription`. Core Data will tell you most of what you want to know about managed objects. – Rob Napier May 09 '18 at 13:53
  • 1
    @RobNapier I see, `setValue(child.value, forKey: label)` is for `NSManagedObject`, the `object` in `Mirror(reflecting: object)` is a swift object. – JIE WANG May 09 '18 at 13:55

1 Answers1

39

Using if case:

You can use if case Optional<Any>.none = a to test if a is nil:

var b: Bool?
var a = b as Any
if case Optional<Any>.none = a {
    print("nil")
} else {
    print("not nil")
}
nil
b = true
a = b as Any
if case Optional<Any>.none = a {
    print("nil")
} else {
    print("not nil")
}
not nil

Using switch:

You can use the pattern test with switch as well:

var b: Bool?
var a = b as Any

switch a {
case Optional<Any>.none:
    print("nil")
default:
    print("not nil")
}
nil
vacawama
  • 150,663
  • 30
  • 266
  • 294