10

After migrating to Swift 3, I get an error when I try and do:

self.publicDB.save(listRecord, completionHandler: { (record, error) -> Void in
        if let saveError = error {
            NSLog("There was an error saving the record: %@", saveError)
        }...

Can someone tell me why this is and what I can do produce an output with relative ease?

The error is NSLog unavailable: variadic function unavailable.

BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156

2 Answers2

12

The problem, despite the "variadic" red herring, is that we no longer get automatic bridging to an Objective-C type; you have to cross the bridge explicitly, yourself. Write saveError as NSError to get an Objective-C style object.

matt
  • 515,959
  • 87
  • 875
  • 1,141
7

NSLog doesn't work with Swift Object and the error that passed by the completion handler is Error not NSError.

So change your code to

self.publicDB.save(listRecord, completionHandler: { (record, error) -> Void in
        if let saveError = error as? NSError {
            NSLog("There was an error saving the record: %@", saveError)
        }...

or write your own implementation of Error that extend CustomDebugStringConvertible protocol

class MyError: Error, CustomDebugStringConvertible {
    var debugDescription: String {
        return "The cause of error is xxx"
    }
}

and then set the completion to emit MyError rather than Error

Niko Adrianus Yuwono
  • 11,012
  • 8
  • 42
  • 64
  • @matt Sorry I didn't mean to copy your answer, maybe it's better if I delete my answer and edit yours? – Niko Adrianus Yuwono Oct 12 '16 at 01:53
  • Alternatively: if you're coding in Swift, ditch `NSLog()` altogether and use `print()` :-) – Nicolas Miari Oct 12 '16 at 02:03
  • 1
    No thanks, that wouldn't be better, in my view. And I don't think you've violated any law. :) – matt Oct 12 '16 at 02:03
  • @NicolasMiari But sometimes there are good reasons to use NSLog. And the question is a fair one; I've run into this problem myself. – matt Oct 12 '16 at 02:04
  • @matt Fair point. Haven't felt the need myself yet, but will look into it. – Nicolas Miari Oct 12 '16 at 02:06
  • 2
    @NicolasMiari And the "variadic" in the error message is highly misleading. The problem is in fact that we no longer get automatic bridging to an Objective-C type; you have to do it yourself. – matt Oct 12 '16 at 02:20
  • I know, right? Typical misleading Swift error message. However, I remember having to cast `String` to `NSString` explicitly before Swift 3 (e.g., with Security.framework). Never understood the details of when `String` can pass as `NSString` and when it can't. Perhaps it's because Keychain is a C API, and bridging with Swift types was an Objective-C-only feature? – Nicolas Miari Oct 12 '16 at 02:25
  • @NikoAdrianusYuwono you would need to write the error as `if let saveError = error as NSError?` – BlackHatSamurai Oct 12 '16 at 02:47