2016-08-02 8 views
47

Nowy w Xcode 8 beta 4, NSError jest zmostkowany do typu protokołu Swift Error. Wpływa to na StoreKit, gdy mamy do czynienia z błędnymi SKPaymentTransaction s. Powinieneś sprawdzić, aby upewnić się, że błąd nie wystąpił, ponieważ transakcja została anulowana, aby dowiedzieć się, czy wyświetlać użytkownikowi komunikat o błędzie. Robisz to, sprawdzając błąd: code. Ale z Error zamiast NSError nie zdefiniowano żadnego code. Nie byłem w stanie dowiedzieć się, jak poprawnie uzyskać kod błędu z Error.Kod dostępu w błędzie Swift 3

To działało w poprzedniej wersji Swift 3:

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

Teraz error jest Error nie NSError, code nie jest członkiem.

+1

Spróbuj 'if (transaction.error jako NSError) .code! = SKErrorCode.PaymentCancelled {' –

+1

To działa, po prostu rzucając go jako' NSError', dzięki @LeoDabus – Joey

Odpowiedz

28

Casting do SKError wydaje się działać dla mnie w Xcode 8 i Swifta 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 
    } 

Nie potrzeba rawValue.

+0

Aktualizuję poprawną odpowiedź na tę, ponieważ jest najbardziej poprawna. Zdecydowanie lepiej to zrobić zamiast przesyłać do 'NSError'. Potwierdzono, że działa. – Joey

+0

Czy to nie wspaniałe? Mam ten sam problem, ale w ALAssets. Ale wydaje się, że nie ma tam odpowiednika SKError –

85

Inną opcją kod dostępu i domen właściwości w Swift 3 rodzaje błędu jest rozszerzenie go następująco:

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

@Joey przykro mi, że byłem na telefonie komórkowym, więc nie mogłem sprawdzić poprawnej składni. –

+2

Sprawdź odpowiedź @ murray-sagal, lepiej jest użyć nowo dostarczonego SKError, zamiast wrócić do obiektów Objective-C. – o15a3d4l11s2

33

Teraz w Xcode 8 i szybki 3 obsada warunkowy jest zawsze udaje się, więc trzeba zrobić następujące:

let code = (error as NSError).code 

i sprawdź code dla swoich potrzeb. Nadzieję, że to pomaga

+0

Dzięki! To rozwiązuje mój problem. – xyzpatience

7

To jest poprawne (własne testy Apple użyć tej metody):

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

Z drugiej strony, rzucając do NSError prawdopodobnie zostanie wkrótce przestarzałe:

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

Czy istnieje link do podejścia stosowanego przez własne testy Apple? –

+0

Cóż, @AndrewPaulSimmons nie było fajnego czystego linku, ale jeśli wypróbujesz repozytorium Git firmy Apple dla Swifta, a następnie wyszukasz "_code", zobaczysz wszystkie własne testy, gdzie zajmują się obiektem błędu w ten sposób. Sprawdź to: https://github.com/apple/swift/search?utf8=%E2%9C%93&q=_code – Rob

+3

Uważasz, że rzucanie zaklęć do odpowiedniej klasy ma sens, ale zewnętrzny dostęp do subskrybowanych elementów jest w porządku? To prawda, że ​​powinieneś mieć dostęp do '.code' w' if let' lub 'guard let', a nie tylko na ślepo, zakładając, że obsada działała. – devios1