I want to track additional information about errors to help support issues and be proactive where errors/bugs are encountered. I am new to iOS/Swift, but I have followed a few YouTube videos and posts on error handling to alert users of an error (this was the most up to date/best one I found) but I also want to provide more detail as well to help support. I created a custom error:
enum CustomError: Error {
case apiDecodingError
...
}
and extended it:
extension CustomError: LocalizedError {
var errorDescription: String? {
switch self {
case .apiDecodingError:
return NSLocalizedString("Problem understanding service response.", comment: "")
...
}
}
}
but I cannot add additional properties to the extension because: Extensions must not contain stored properties.
When I catch and throw a custom error from, for example, decoding the response of an api call:
} catch let DecodingError.keyNotFound(key, context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
throw CustomError.DecodingError
This makes for a simplified user message:
but I also want to send the detail to the bug tracking system with the specific problem, such as the key which was having the problem.
} catch {
print("\(error)")
let properties = ["Error" : error.localizedDescription]
Analytics.trackEvent("UpdateNotificationSetting", withProperties: properties, flags: .critical)
isAlertErrorPresented = true
errorAlert = ErrorAlert(error: error)
}
I would like to send along the detail but that means the custom error needs additional information from the inner error. I'm a novice at SwiftUI, is there a standard way to address this?
You can do it by expanding CustomError
enum CustomError: LocalizedError{
///Takes in any error and makes it compatible with `LocalizedError`
case error(Error)
///Allows for throwing an error with a custom description
case custom(description: String, failureReason: String? = nil, helpAnchor: String? = nil, recoverySuggestion: String? = nil)
///Can be used as a custom key using localization features
case customKey
///Mimic your decoding error
case apiDecodingError(key: String, path: String)
var errorDescription: String?{
switch self{
case .error(let error):
return error.localizedDescription
case .custom(let description, _ , _, _):
return description
case .apiDecodingError(let key, path: let path):
return String(format: "Key %# not found: codingPath: %#", key, path)
default:
///Add `customKeyErrorDescription` to Localizable.strings
return NSLocalizedString("\(self)" + "ErrorDescription", comment: "AppError")
}
}
var failureReason: String?{
switch self{
case .error(let error):
let nsError = error as NSError
return nsError.localizedFailureReason
case .custom(_ , let failureReason , _, _):
return failureReason
case .apiDecodingError(_, _):
return nil
default:
///Add `customKeyFailureReason` to Localizable.strings
return NSLocalizedString("\(self)" + "FailureReason", comment: "AppError")
}
}
var helpAnchor: String?{
switch self{
case .error(let error):
let nsError = error as NSError
return nsError.helpAnchor
case .custom(_ , _ , let helpAnchor, _):
return helpAnchor
case .apiDecodingError(_, _):
return nil
default:
///Add `customKeyHelpAnchor` to Localizable.strings
return NSLocalizedString("\(self)" + "HelpAnchor", comment: "AppError")
}
}
var recoverySuggestion: String?{
switch self{
case .error(let error):
let nsError = error as NSError
return nsError.localizedRecoverySuggestion
case .custom(_, _ , _, let recoverySuggestion):
return recoverySuggestion
case .apiDecodingError(_, _):
return nil
default:
///Add `customKeyRecoverySuggestion` to Localizable.strings
return NSLocalizedString("\(self)" + "RecoverySuggestion", comment: "AppError")
}
}
}
Then you can pass along any standard error
do{
}catch{
CustomError.error(error)
}
Related
this is how I call to api
func userLogin(login : Login) {
let l = login
print("login values are : \(l)")
let UrlRequest = Router.userLogin(login).urlRequest
Alamofire.request(UrlRequest!).responseObject { (response : DataResponse<TheResponse>) in
switch response.result {
case .success(let data):
if (data.status != 200) {
print("Error message : \(data.errorMessage)")
}
else {
print("success")
}
break
case .failure(let Error):
print("some error occur : \(Error.localizedDescription)")
break
}
}
}
}
but always goes to error with this some error occur : The operation couldn’t be completed. ObjectMapper failed to serialize response.. I'm using Alamofire with swift 3. How can I overcome this problem. hope your help with this.
Your code does not have any problem. The JSON in URL is malformed
Using swift 3.0, I am trying to create enum where different values and their description will get as per enum type, depends on localization language. But below code is not compile due to Bundle parameters are not valid as here self is not valid class in enum. Any suggestion about how can we resolve this issue for localization?
public enum TempEnumValues : Int
{
case first
case second
case third
var values: Int
{
switch self
{
case .first:
return 1
case .second:
return 2
case .third:
return 3
}
}
var description: String
{
let bundle = Bundle(for: CLASS_NAME.self))
switch self
{
case .first:
return NSLocalizedString("First Value", bundle: bundle, comment: "")
case .second:
return NSLocalizedString("Second Value", bundle: bundle, comment: "")
case .third:
return NSLocalizedString("Third Value", bundle: bundle, comment: "")
}
}
}
I found the answer & updated code
I have old code:
func htmlToText(encodedString:String) -> String?
{
let encodedData = encodedString.dataUsingEncoding(NSUTF8StringEncoding)!
do
{
return try NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil).string
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
}
and I want to translate it to swift 3, now i have:
let encodedData = encodedString.data(using: String.Encoding.utf8)!
do
{
return try NSAttributedString(data: encodedData, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:String.Encoding.utf8], documentAttributes: nil).string
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
This code generate error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue unsignedIntegerValue]: unrecognized selector sent to instance 0x608000251d30'
I have no idea what could went wrong. Can anybody help me?
String.Encoding is a Swift struct, which cannot be passed to Objective-C world. When Swift find such things in Any, it generates _SwiftValue which is completely useless in Objective-C.
Try this:
return try NSAttributedString(data: encodedData, options: [
NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute:String.Encoding.utf8.rawValue
], documentAttributes: nil).string
I am working on facebook integration in xcode 8 Swift 3.
i have used the following code
let parameters = ["fields": "email, first_name, last_name, picture.type(large)"]
FBSDKGraphRequest.init(graphPath: "me", parameters: parameters).start { (connection, result, error) in
if error != nil{
print(error)
return
}
But I am getting below error.
Optional(Error Domain=com.facebook.sdk.core Code=8 "(null)" UserInfo={com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey=0, com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey=400, com.facebook.sdk:FBSDKErrorDeveloperMessageKey=An active access token must be used to query information about the current user., com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode=2500, com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey={
body = {
error = {
code = 2500;
"fbtrace_id" = "FmK/8QACfhe";
message = "An active access token must be used to query information about the current user.";
type = OAuthException;
};
};
code = 400;
}})
can anyone help me out this ??
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
print("Login buttoon clicked")
let graphRequest:FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"first_name, gender, last_name, email, picture.type(large)"])
graphRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil)
{
print("Error: \(error)")
}
else
{
let data:[String:AnyObject] = result as! [String : AnyObject]
print(data["first_name"]!)
print(data["last_name"]!)
print(data["email"]!)
print(data["id"]!)
print(data["gender"]!)
}
})
}
I'm hoping someone may be able to help me figure out a snafu I'm having with an app I am trying to write (or learn to write) in Swift 2.0. This previously worked in Swift 1.2, but after the necessary conversions, I am continunally facing the error;
Cannot invoke initializer of type 'NSData' with an argument list of type '(contenOfURL: NSURL, options: NSDataReadingOptions, error:nil)'
Here is my code, slightly truncated, that I am using;
...
class func fetchMinionData() -> [Minion] {
let myURL = "https://myurl/test.json"
let dataURL = NSURL(string: myURL)
let data = NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: nil)
//THIS IS THE LINE THAT THROWS THE ERROR
let minionJSON = JSON(data)
var minions = [Minion]()
for (_ , minionDictionary) in minionJSON {
minions.append(Minion(minionDetails: minionDictionary))
}
return minions
}
...
Note that I plan to use the SwiftyJSON library to further parse the data once it is downloaded. I am searching endlessly online, but I just can't seem to figure this out! Thank you!
If you are working with Swift 2, you should not pass the last argument "error". Instead put a try around the NSData initialization. If data needs to be accessed outside take the init result in a var and convert to let Modified code
var optData:NSData? = nil
do {
optData = try NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe)
}
catch {
print("Handle \(error) here")
}
if let data = optData {
// Convert data to JSON here
}
Example code for Dictionary :) Swift 2.0
https://github.com/DaRkD0G/LoadExtension/edit/master/LoadExtensionDictionary.swift
enum EHError: ErrorType {
case Nil(String)
case NSData(String)
case JSON(String)
}
extension Dictionary {
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: PathForResource / NSData / JSON
- returns: Dictionary<String, AnyObject>
*/
static func loadJSONFromBundle(filename: String) throws -> Dictionary<String, AnyObject> {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? Dictionary<String, AnyObject> else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization]Error.InvalidJSON Level file '\(filename)' is not valid JSON")
}
return jsonDict
}
}
If I do not do a mistake, for you is that
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: EHError : PathForResource / NSData / JSON
- returns: [String : AnyObject]
*/
static func loadJSONFromBundle(filename: String, nameJson:String) throws -> [String : AnyObject] {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String : AnyObject] else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization] Invalid JSON\n nameJson '\(nameJson)'\nFile '\(filename)'")
}
return jsonDict
}