7

Aim

  • I would like to display the CKError encountered to the user in the app as an alert.
  • So I would like to extract the string from the error that can be displayed to the user.

Note: This question is not about UI code to display. Just want to extract a meaningful string from the error.

I tried to use localizedDescription but it doesn't seem to contain an appropriate string

Code:

Given below are the attempts I made:

po error  
<CKError 0x1c464cea0: "Network Unavailable" (3/NSURLErrorDomain:-1009); "The Internet connection appears to be offline.">  

po error.localizedDescription  
"The operation couldn’t be completed. (CKErrorDomain error 3.)"  

po (error as! CKError).errorUserInfo  
▿ 2 elements  
  ▿ 0 : 2 elements  
    - key : "NSUnderlyingError"  
    - value : Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSErrorFailingURLStringKey=https:/  
  ▿ 1 : 2 elements  
    - key : "NSDebugDescription"  
    - value : NSURLErrorDomain: -1009  



po (error as? NSError)?.localizedFailureReason  
nil  

po (error as? NSError)?.localizedRecoverySuggestion  
nil  

po (error as? NSError)?.localizedRecoveryOptions  
nil  

po (error as? NSError)?.debugDescription  
▿ Optional<String>  
  - some : "<CKError 0x1c064eaf0: \"Network Unavailable\" (3/NSURLErrorDomain:-1009); \"The Internet connection appears to be offline.\">"  

Questions:

The debug description seems to be the closest to what I want.

  1. Am I missing something ?
  2. What is the correct way to extract the error string that I can display to the user ?
picciano
  • 21,170
  • 9
  • 62
  • 81
user1046037
  • 14,608
  • 12
  • 79
  • 117

3 Answers3

5

Looks like there is another error in the errorUserInfo[NSUnderlyingError]. Try getting the localizedDescription from that error.

So, that would be:

((error as? CKError)?.errorUserInfo[NSUnderlyingErrorKey] as? NSError)?.localizedDescription
Richard Venable
  • 7,317
  • 2
  • 38
  • 45
  • It returns It returns `Optional(Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSErrorFailingURLStringKey=https://gateway.icloud.com:443/ckdatabase/api/client/query/retrieve, NSErrorFailingURLKey=https://gateway.icloud.com:443/ckdatabase/api/client/query/retrieve, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=The Internet connection appears to be offline.})` This would be too technical for the user to understand – user1046037 Apr 19 '18 at 16:33
  • I just feel it is a bug for CKError, the localizedDescription is not suitably populated. – user1046037 Apr 19 '18 at 16:34
  • The localized description in your comment is “The Internet connection appears to be offline.”. That’s what you need. – Richard Venable Apr 25 '18 at 12:03
  • It is not a separate key `NSLocalizedDescription`, it is a small portion of a long error message. So it wouldn't be reliable to extract it like that. – user1046037 Apr 25 '18 at 15:47
  • No, there is a separate error inside of there. I updated my answer with the code to help you pull it out. – Richard Venable Apr 30 '18 at 19:49
  • Awesome !!! Works great. Made my day ... thank you so much !!! Have you already been using this or just discovered it ? – user1046037 May 01 '18 at 01:49
4

The error.localizedDescription is really all you have to work with from the error itself.

Your app can provide a better error message (more user-friendly, localized, etc.) by checking for the error code and providing its own message to the user.

(error as? NSError)?.code
picciano
  • 21,170
  • 9
  • 62
  • 81
  • Unfortunately localized description doesn’t provide a meaningful description. Well problem with handling my own error message is that there are 26 error codes. And if I support 5 languages then it is 26 x 5 = 130 error messages. Sadly they do have the error in debug description but with technical info. I think it is more of a bug was wondering if there was a solution – user1046037 Apr 20 '18 at 01:10
0

I'm not proud of it, but this is what I resorted to. There must be a better way!

public func ckErrorCodeToText(code: CKError.Code) -> String {
    switch code {
    case .alreadyShared: return "alreadyShared"
    case .internalError: return "internalError"
    case .partialFailure: return "partialFailure"
    case .networkUnavailable: return "networkUnavailable"
    case .networkFailure: return "networkFailure"
    case .badContainer: return "badContainer"
    case .serviceUnavailable: return "serviceUnavailable"
    case .requestRateLimited: return "requestRateLimited"
    case .missingEntitlement: return "missingEntitlement"
    case .notAuthenticated: return "notAuthenticated"
    case .permissionFailure: return "permissionFailure"
    case .unknownItem: return "unknownItem"
    case .invalidArguments: return "invalidArguments"
    case .resultsTruncated: return "resultsTruncated"
    case .serverRecordChanged: return "serverRecordChanged"
    case .serverRejectedRequest: return "serverRejectedRequest"
    case .assetFileNotFound: return "assetFileNotFound"
    case .assetFileModified: return "assetFileModified"
    case .incompatibleVersion: return "incompatibleVersion"
    case .constraintViolation: return "constraintViolation"
    case .operationCancelled: return "operationCancelled"
    case .changeTokenExpired: return "changeTokenExpired"
    case .batchRequestFailed: return "batchRequestFailed"
    case .zoneBusy: return "zoneBusy"
    case .badDatabase: return "badDatabase"
    case .quotaExceeded: return "quotaExceeded"
    case .zoneNotFound: return "zoneNotFound"
    case .limitExceeded: return "limitExceeded"
    case .userDeletedZone: return "userDeletedZone"
    case .tooManyParticipants: return "tooManyParticipants"
    case .referenceViolation: return "referenceViolation"
    case .managedAccountRestricted: return "managedAccountRestricted"
    case .participantMayNeedVerification: return "participantMayNeedVerification"
    case .serverResponseLost: return "serverResponseLost"
    case .assetNotAvailable: return "assetNotAvailable"
    @unknown default: return String(code.rawValue)
    }
}
Tom Wilson
  • 31
  • 3