Jordan H
Jordan H

Reputation: 55865

Accessing code in Swift 3 Error

New in Xcode 8 beta 4, NSError is bridged to the Swift Error protocol type. This affects StoreKit when dealing with failed SKPaymentTransactions. You ought to check to be sure the error didn't occur because the transaction was cancelled to know whether or not to show an error message to the user. You do this by examining the error's code. But with Error instead of NSError, there is no code defined. I haven't been able to figure out how to properly get the error code from Error.

This worked in the previous version of Swift 3:

func failedTransaction(_ transaction: SKPaymentTransaction) {
    if let transactionError = transaction.error {
        if transactionError.code != SKErrorCode.paymentCancelled.rawValue {
            //show error to user
        }
     }
     ...
}

Now that error is an Error not NSError, code is not a member.

Upvotes: 75

Views: 52867

Answers (6)

Codetard
Codetard

Reputation: 2605

A lot is changing. Here's update for Xcode 11.

if let skError = transaction.error as? SKError, skError.code == .paymentCancelled { print("Cancelled") }

Upvotes: 0

Gurjit Singh
Gurjit Singh

Reputation: 1913

Use

error._code == NSURLErrorCancelled

to match the error code.

Upvotes: 0

Leo Dabus
Leo Dabus

Reputation: 236528

Another option to access code and domain properties in Swift 3 Error types is extending it as follow:

extension Error {
    var code: Int { return (self as NSError).code }
    var domain: String { return (self as NSError).domain }
}

Upvotes: 142

Rob
Rob

Reputation: 5954

This is correct (Apple's own tests use this approach):

if error._code == SKError.code.paymentCancelled.rawValue { ... }

On the other hand, casting to NSError will probably be deprecated soon:

let code = (error as NSError).code // CODE SMELL!!
if code == SKError.code.paymentCancelled.rawValue { ... }

Upvotes: 11

Murray Sagal
Murray Sagal

Reputation: 8674

Casting to SKError seems to be working for me in xCode 8 and Swift 3...

    guard let error = transaction.error as? SKError else {return}
    switch error.code {  // https://developer.apple.com/reference/storekit/skerror.code
    case .unknown: break
    case .paymentCancelled: break
    case .clientInvalid: break
    case .paymentInvalid: break
    case .paymentNotAllowed: break
    case .cloudServiceNetworkConnectionFailed: break
    case .cloudServicePermissionDenied: break
    case .storeProductNotAvailable: break
    }

No need for rawValue.

Upvotes: 42

Andrey M.
Andrey M.

Reputation: 3079

Now in Xcode 8 and swift 3 the conditional cast is always succeeds, so you need do following:

let code = (error as NSError).code

and check the code for your needs. Hope this helps

Upvotes: 57

Related Questions