swift programming NSErrorPointer error etc
These types and methods have changed a lot since Swift 1.
- The
NS
prefix is dropped - The methods now throw exceptions instead of taking an error pointer
- Use of NSDictionary is discouraged. Instead use a Swift dictionary
This results in the following code:
do {
let object = try JSONSerialization.jsonObject(
with: responseData,
options: .allowFragments)
if let dictionary = object as? [String:Any] {
// do something with the dictionary
}
else {
print("Response data is not a dictionary")
}
}
catch {
print("Error parsing response data: \(error)")
}
Of, if you don't care about the specific parsing error:
let object = try JSONSerialization.jsonObject(
with: responseData,
options: .allowFragments)
if let dictionary = object as? [String:Any] {
// do something with the dictionary
}
else {
print("Response data is not a dictionary")
}
Original Answer
Your NSError has to be defined as an Optional
because it can be nil:
var error: NSError?
You also want to account for there being an error in the parsing which will return nil
or the parsing returning an array. To do that, we can use an optional casting with the as?
operator.
That leaves us with the complete code:
var possibleData = NSJSONSerialization.JSONObjectWithData(
responseData,
options:NSJSONReadingOptions.AllowFragments,
error: &error
) as? NSDictionary;
if let actualError = error {
println("An Error Occurred: \(actualError)")
}
else if let data = possibleData {
// do something with the returned data
}
What is this NSErrorPointer type?
I suggest you read the Pointers section of the Using Swift with Cocoa and Objective-C guide: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_16
There is a table at the bottom of the Pointers section, which explains how class pointers bridge to Swift pointer types. Based on that, the NSError pointer should be AutoreleasingUnsafePointer<NSError>
. Searching trough the headers for NSErrorPointer yields this:
typealias NSErrorPointer = AutoreleasingUnsafePointer<NSError?>
Why the extra ?
after NSError
? I guess it's because NSError can also be nil
.
Hope it helps!
Error-Handling in Swift-Language
Swift 2 & 3
Things have changed a bit in Swift 2, as there is a new error-handling mechanism, that is somewhat more similar to exceptions but different in detail.
1. Indicating error possibility
If function/method wants to indicate that it may throw an error, it should contain throws
keyword like this
func summonDefaultDragon() throws -> Dragon
Note: there is no specification for type of error the function actually can throw. This declaration simply states that the function can throw an instance of any type implementing ErrorType or is not throwing at all.
2. Invoking function that may throw errors
In order to invoke function you need to use try keyword, like this
try summonDefaultDragon()
this line should normally be present do-catch block like this
do {
let dragon = try summonDefaultDragon()
} catch DragonError.dragonIsMissing {
// Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
// Other specific-case error-handlng
} catch {
// Catch all error-handling
}
Note: catch clause use all the powerful features of Swift pattern matching so you are very flexible here.
You may decided to propagate the error, if your are calling a throwing function from a function that is itself marked with throws
keyword:
func fulfill(quest: Quest) throws {
let dragon = try summonDefaultDragon()
quest.ride(dragon)
}
Alternatively, you can call throwing function using try?
:
let dragonOrNil = try? summonDefaultDragon()
This way you either get the return value or nil, if any error occurred. Using this way you do not get the error object.
Which means that you can also combine try?
with useful statements like:
if let dragon = try? summonDefaultDragon()
or
guard let dragon = try? summonDefaultDragon() else { ... }
Finally, you can decide that you know that error will not actually occur (e.g. because you have already checked are prerequisites) and use try!
keyword:
let dragon = try! summonDefaultDragon()
If the function actually throws an error, then you'll get a runtime error in your application and the application will terminate.
3. Throwing an error
In order to throw an error you use throw keyword like this
throw DragonError.dragonIsMissing
You can throw anything that conforms to ErrorType
protocol. For starters NSError
conforms to this protocol but you probably would like to go with enum-based ErrorType
which enables you to group multiple related errors, potentially with additional pieces of data, like this
enum DragonError: ErrorType {
case dragonIsMissing
case notEnoughMana(requiredMana: Int)
...
}
Main differences between new Swift 2 & 3 error mechanism and Java/C#/C++ style exceptions are follows:
- Syntax is a bit different:
do-catch
+try
+defer
vs traditionaltry-catch-finally
syntax. - Exception handling usually incurs much higher execution time in exception path than in success path. This is not the case with Swift 2.0 errors, where success path and error path cost roughly the same.
- All error throwing code must be declared, while exceptions might have been thrown from anywhere. All errors are "checked exceptions" in Java nomenclature. However, in contrast to Java, you do not specify potentially thrown errors.
- Swift exceptions are not compatible with ObjC exceptions. Your
do-catch
block will not catch any NSException, and vice versa, for that you must use ObjC. - Swift exceptions are compatible with Cocoa
NSError
method conventions of returning eitherfalse
(forBool
returning functions) ornil
(forAnyObject
returning functions) and passingNSErrorPointer
with error details.
As an extra syntatic-sugar to ease error handling, there are two more concepts
- deferred actions (using
defer
keyword) which let you achieve the same effect as finally blocks in Java/C#/etc - guard statement (using
guard
keyword) which let you write little less if/else code than in normal error checking/signaling code.
Swift 1
Runtime errors:
As Leandros suggests for handling runtime errors (like network connectivity problems, parsing data, opening file, etc) you should use NSError
like you did in ObjC, because the Foundation, AppKit, UIKit, etc report their errors in this way. So it's more framework thing than language thing.
Another frequent pattern that is being used are separator success/failure blocks like in AFNetworking:
var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
success: { (NSURLSessionDataTask) -> Void in
println("Success")
},
failure:{ (NSURLSessionDataTask, NSError) -> Void in
println("Failure")
})
Still the failure block frequently received NSError
instance, describing the error.
Programmer errors:
For programmer errors (like out of bounds access of array element, invalid arguments passed to a function call, etc) you used exceptions in ObjC. Swift language does not seem to have any language support for exceptions (like throw
, catch
, etc keyword). However, as documentation suggests it is running on the same runtime as ObjC, and therefore you are still able to throw NSExceptions
like this:
NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()
You just cannot catch them in pure Swift, although you may opt for catching exceptions in ObjC code.
The questions is whether you should throw exceptions for programmer errors, or rather use assertions as Apple suggests in the language guide.
How do I parse an array inside parsed JSON in Swift?
Dictionary access in Swift returns an Optional, so you need to force the value (or use the if let
syntax) to use it.
This works:parsedJSON["boards"]![0]
(It probably shouldn't crash Xcode, though)
Synchronous URL request on Swift 2
There is a reason behind deprecation - there is just no use for it. You should avoid synchronous network requests as a plague. It has two main problems and only one advantage (it is easy to use.. but isn't async as well?):
- The request blocks your UI if not called from different thread, but if you do that, why don't use asynchronous handler right away?
- There is no way how to cancel that request except when it errors on its own
Instead of this, just use asynchronous request:
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
})
iOS9 Deprecation
Since in iOS9 this method is being deprecated, I suggest you to use NSURLSession instead:
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
How can I use NSError in my iPhone App?
Well, what I usually do is have my methods that could error-out at runtime take a reference to a NSError
pointer. If something does indeed go wrong in that method, I can populate the NSError
reference with error data and return nil from the method.
Example:
- (id) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:@"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
*error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
We can then use the method like this. Don't even bother to inspect the error object unless the method returns nil:
// initialize NSError object
NSError* error = nil;
// try to feed the world
id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!yayOrNay) {
// inspect error
NSLog(@"%@", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
We were able to access the error's localizedDescription
because we set a value for NSLocalizedDescriptionKey
.
The best place for more information is Apple's documentation. It really is good.
There is also a nice, simple tutorial on Cocoa Is My Girlfriend.
Related Topics
App Crashes When Playing Audio on iOS13.1
Swiftui Navigation on iPad - How to Show Master List
Converting .M4A File to .Aiff Using Audioconverter Swift
Asyncdetached Falling Back into Main Thread After Mainactor Call
Spawning a Spritekit Node at a Random Time
Swift: Loop Over Array Elements and Access Previous and Next Elements
The File "Xxx.Mp4" Couldn't Be Opened Because You Don't Have Permission to View It
How to Install the Alamofire 4.0 in Xcode 8.0
Why Do I Need to Declare an Optional Value as Nil Explicitly in Struct - Swift
Error: Bool Is Not Convertible to Void:
Fbsdkapplicationdelegate Application Openurl:Sourceapplication:Annotation Deprecated
Swift Programming Nserrorpointer Error etc
How to Use .Svg Images in Swiftui
How to Use Dispatch Groups to Wait to Call Multiple Functions That Depend on Different Data
Masking Uiview/Uiimageview to Cutout Transparent Text
My Data Changes in Uitableviewcell When I Scroll Down and Get Back