How to use FirebaseAuth error codes? - ios

I'm trying to use the AuthErrorCode in Firebase but I keep getting errors. Here is my code:
private func handleErrors(err: NSError, loginHandler: LoginHandler?) {
if let errCode = AuthErrorCode(rawValue: err.code) {
switch errCode {
case .errorCodeWrongPassword: //Enum case 'errorCodeWrongPassword' not found in type 'AuthErrorCode'
loginHandler?(LoginErrorCode.WRONG_PASSWORD)
break
case .errorCodeInvalidEmail: //Enum case 'errorCodeInvalidEmail' not found in type 'AuthErrorCode'
loginHandler?(LoginErrorCode.INVALID_EMAIL)
break
case .errorCodeUserNotFound: //Enum case 'errorCodeUserNotFound' not found in type 'AuthErrorCode'
loginHandler?(LoginErrorCode.USER_NOT_FOUND)
break
case .errorCodeEmailAlreadyInUse: //Enum case 'errorCodeEmailAlreadyInUse' not found in type 'AuthErrorCode'
loginHandler?(LoginErrorCode.EMAIL_ALREADY_IN_USE)
break
case .errorCodeWeakPassword: //Enum case 'errorCodeWeakPassword' not found in type 'AuthErrorCode'
loginHandler?(LoginErrorCode.WEAK_PASSWORD)
break
default:
loginHandler?(LoginErrorCode.PROBLEM_CONNECTING)
break
}
}
}
Anyone know what I'm doing wrong? If you didn't see the errors in my code here they are:
Enum case 'errorCodeWrongPassword' not found in type 'AuthErrorCode'
Enum case 'errorCodeInvalidEmail' not found in type 'AuthErrorCode'
Enum case 'errorCodeUserNotFound' not found in type 'AuthErrorCode'
Enum case 'errorCodeEmailAlreadyInUse' not found in type 'AuthErrorCode'
Enum case 'errorCodeWeakPassword' not found in type 'AuthErrorCode'
Let me know if you guys have any ideas!

They are imported in Swift as AuthErrorCode.weakPassword for example: remove errorCode from all the case values.
private func handleErrors(err: NSError, loginHandler: LoginHandler?) {
guard let errCode = AuthErrorCode(rawValue: err.code)
else { return }
switch errCode {
case .wrongPassword:
loginHandler?(LoginErrorCode.WRONG_PASSWORD) // Transform to wrongPassword
case .invalidEmail:
loginHandler?(LoginErrorCode.INVALID_EMAIL)
case .userNotFound:
loginHandler?(LoginErrorCode.USER_NOT_FOUND)
case .emailAlreadyInUse:
loginHandler?(LoginErrorCode.EMAIL_ALREADY_IN_USE)
case .weakPassword:
loginHandler?(LoginErrorCode.WEAK_PASSWORD)
default:
loginHandler?(LoginErrorCode.PROBLEM_CONNECTING)
}
}
Swift suggestions:
Don't use break in switch statements, they break by default after the case is done (fallthrough allows you to check each case after a match)
Switch NSError for Error (Firebase uses NSError, if you want to switch to Error read Swift 4 get error code from error)
Is LoginErrorCode your custom class ? Consider switching to Swift >= 3 syntax for the cases (lower camel case)

Related

A better way to match error code with enum describing error

I have an enum describing various error codes that can be returned from a server:
public enum LoginError: Int, Error {
case missingUsername = 30001
case missingPassword = 30002
case incorrectPassword = 30003
case unknownUser = 30005
case couldNotBeLoaded = 31002
case sessionExpired = 31001
case unknownError = 30000
}
The server returns the error in the response body. I'm decoding the result and getting the error code, and then matching the error code with the enum:
let decoder = JSONDecoder()
let loginResult = try decoder.decode(LoginResult.self, from: data)
if loginResult.success {
return .success(loginResult)
} else {
switch loginResult.errorCode as! Error {
case LoginError.incorrectPassword:
return .failure(.incorrectPassword)
case LoginError.missingUsername:
return .failure(.missingUsername)
case LoginError.missingPassword:
return .failure(.missingPassword)
case LoginError.unknownUser:
return .failure(.unknownUser)
case LoginError.couldNotBeLoaded:
return .failure(.couldNotBeLoaded)
case LoginError.sessionExpired:
return .failure(.sessionExpired)
default:
return .failure(.unknownError)
}
}
For one, this crashes because I can't cast the LoginError Int type to Error, but also, there must be a more elegant way than this long switch statement. I feel like there's some basic bit of Swift syntax I've missed here. Is there a one-liner that could replace this?

How can I access Success/Failure cases from this struct?

Using Alamofire v4.0, Alamofire.upload() using MultipartFormData has changed, but I can't find out how to get the success/error case with the enumeration returned in the closure (type is SessionManager.MultipartFormDataEncodingResult)
Looking into the SessionManager.MultipartFormDataEncodingResult struct, here is what I get:
public enum MultipartFormDataEncodingResult {
case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)
case failure(Error)
}
So Xcode seems to have been super unhelpful here and autocompleted the initialiser for that enum rather than the case statement. You would want to do something similar to what you have for the .failure case:
switch encodingResult {
case .success(let request, let streamingFromDisk, let streamFileURL):
// you can now access request, streamingFromDisk and streamFileURL in this scope
...
case .failure(let errorType):
// you can now access errorType in this scope
...
}

Use of unresolved identifier when using StoreKit constants with iOS 9.3/Xcode 7.3

I get the error "Use of unresolved identifier" when trying to use one of these StoreKit constants:
SKErrorClientInvalid
SKErrorPaymentCancelled
SKErrorPaymentInvalid
SKErrorPaymentNotAllowed
SKErrorStoreProductNotAvailable
SKErrorUnknown
Your code may look like this:
if transaction.error!.code == SKErrorPaymentCancelled {
print("Transaction Cancelled: \(transaction.error!.localizedDescription)")
}
What changed? Is there a new module I need to import?
As of iOS 9.3 certain StoreKit constants have been removed from the SDK. See StoreKit Changes for Swift for the full list of changes.
These constants have been replaced in favor of the SKErrorCode enum and associated values:
SKErrorCode.ClientInvalid
SKErrorCode.CloudServiceNetworkConnectionFailed
SKErrorCode.CloudServicePermissionDenied
SKErrorCode.PaymentCancelled
SKErrorCode.PaymentInvalid
SKErrorCode.PaymentNotAllowed
SKErrorCode.StoreProductNotAvailable
SKErrorCode.Unknown
You should check be checking your transaction.error.code with the enum's rawValue. Example:
private func failedTransaction(transaction: SKPaymentTransaction) {
print("failedTransaction...")
if transaction.error?.code == SKErrorCode.PaymentCancelled.rawValue {
print("Transaction Cancelled: \(transaction.error?.localizedDescription)")
}
else {
print("Transaction Error: \(transaction.error?.localizedDescription)")
}
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
}
You should be checking against these error codes rather than the legacy constants if creating a new application using StoreKit on iOS 9.3 and above.
Adding to #JAL answer heres a switch variant
switch (transaction.error!.code) {
case SKErrorCode.Unknown.rawValue:
print("Unknown error")
break;
case SKErrorCode.ClientInvalid.rawValue:
print("Client Not Allowed To issue Request")
break;
case SKErrorCode.PaymentCancelled.rawValue:
print("User Cancelled Request")
break;
case SKErrorCode.PaymentInvalid.rawValue:
print("Purchase Identifier Invalid")
break;
case SKErrorCode.PaymentNotAllowed.rawValue:
print("Device Not Allowed To Make Payment")
break;
default:
break;
}
None of the above answers worked for me. What solved it was prepending StoreKit to the SKError.
My switch looked something like this:
switch (transaction.error!.code) {
case StoreKit.SKErrorCode.Unknown.rawValue:
print("Unknown error")
break;
}
No idea why.

How can I access the associated values of SwiftyDropbox errors?

I’ve been working with SwiftyDropbox and I’m having a curious problem with errors. Specifically, I’m not sure how to manipulate errors in the closure callbacks provided after responses are received so that I can get at their associated values.
For instance, the completion handler for Dropbox.authorizedClient.filesListFolder provides a
CallError<(Files.ListFolderError)>?
to work with. How would I go about checking if it is a
CallError.HTTPError
, so that I can get the HTTP error code out of it? Right now I’m just sucking that information out of the error’s .description but that doesn’t seem like the right way to do it.
This is what I’ve tried. I suspect I’m failing to understand something with the generics involved.
client.filesListFolder(path: "", recursive: false).response({ (listFolderResult, listFolderError) -> Void in
switch listFolderError {
case let .HTTPError(code, message, requestId):
print("http error")
default:
print("not a http error")
}
Enum case 'HTTPError' not found in type 'CallError?'
The problem here is that we're trying to switch on an optional. This simpler example highlights the exact same problem:
enum Foo {
case a
case b
}
let x: Foo? = nil
switch x {
case .a:
print("a")
case .b:
print("b")
}
Enum case 'a' not found in type 'Foo?'
We can switch over optionals because Optional is itself an Enum, with two cases: None and Some(T).
So when we're switching over an optional, Swift expects some code like this:
switch someOptional {
case .Some(someValue):
print("do some things")
case .None:
print("someOptional was nil")
}
But that's probably not necessarily particularly useful to use. We have an optional enum, and ultimately, if we dealt with our optional in a switch, we'd just have nested switch statements. Instead, we should deal with our optional in the normal Swift way of dealing with optionals:
if let error = listFolderError {
switch error {
case let .HTTPError(code, message, requestID):
print("http error")
default:
print("some other error")
}
} else {
print("there was no error")
}

Enum case switch not found in type

Can someone please help me with this.
I have the following public enum
public enum OfferViewRow {
case Candidates
case Expiration
case Description
case Timing
case Money
case Payment
}
And the following mutableProperty:
private let rows = MutableProperty<[OfferViewRow]>([OfferViewRow]())
In my init file I use some reactiveCocoa to set my MutableProperty:
rows <~ application.producer
.map { response in
if response?.application.status == .Applied {
return [.Candidates, .Description, .Timing, .Money, .Payment]
} else {
return [.Candidates, .Expiration, .Description, .Timing, .Money, .Payment]
}
}
But now the problem, when I try to get the value of my enum inside my rows it throws errors. Please look at the code below.
func cellViewModelForRowAtIndexPath(indexPath: NSIndexPath) -> ViewModel {
guard
let row = rows.value[indexPath.row],
let response = self.application.value
else {
fatalError("")
}
switch row {
case .Candidates:
// Do something
case .Expiration:
// Do something
case .Description:
// Do something
case .Timing:
// Do something
case .Money:
// Do something
case .Payment:
// Do something
}
}
It throws an error: Enum case 'some' not found in type 'OfferViewRow on the line let row = rows.value[indexPath.row]
And on every switch statements it throws: Enum case 'Candidates' not found in type '<<Error type>>
Can someone help me with this?
The guard statement wants an optional, as hinted by "Enum case 'some'" in the error message.
But rows.value[indexPath.row] is not Optional<OfferViewRow>, it is a raw OfferViewRow. So it won't enter a guard statement.
Move let row = rows.value[indexPath.row] one line up: Swift takes care of bounds checking, and will crash if indexPath.row is out of bounds.

Resources