fatal error: unexpectedly found nil while unwrapping an Optional value in Swift when tried to parse JSON - cocoa

I've tried to build up a document-based Cocoa app and when I tried to parse JSON in readFromData: ofType: error: method, I got an error: fatal error: unexpectedly found nil while unwrapping an Optional value. The actual line that caused the error is the following:
override func readFromData(data: NSData?, ofType typeName: String?, error outError: NSErrorPointer) -> Bool {
var error: NSErrorPointer!
var loadedDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: error) as? NSDictionary // this causes an error
return true
}
It looks like the NSJSONSerialization.JSONObjectWithData() method caused the error, but why did it issue it?
I changed options: argument to either nil or 0, and also changed error: argument to nil, but nothing solved the issue.
I also ensured that data is not nil.
So what am I missing? I think the JSON method tried to force unwrapping within it, but how can I know that? And how can I escape the fatal error and have my app run properly?
I use Xcode6-beta 3 on Yosemite beta3.

Most likely the problem is that you have data that isn't actually JSON, so the deserialisation will return nil, or the data is an array, and converting it to a dictionary will obviously crash.
You don't seem to understand some of the basics. What do you think AllowFragments is going to achieve? And why did you change error to nil? Do you understand what the error variable is there for? It's there to tell you what errors the JSON parser found. By setting the variable to nil, you prevent it from helping you.

If the data does not contain a valid JSON object, the JSONObjectWithData function will return a nil, so you need to do a conditional unwrapping as follows:
if let dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: jsonError) as? NSDictionary {
println("Dictionary: \(dict)")
} else {
println("nil")
let resultString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Flawed JSON String: \(resultString)")
}
I hope it helps..... e

In this case outError is supplied as an argument so you should use it (I overlooked that).
Looks like this function's purpose is to check whether data is valid JSON.
Then your funciton should be:
override func readFromData(data: NSData?, ofType typeName: String?, error outError: NSErrorPointer) -> Bool {
if let loadedDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: outError) as? NSDictionary {
return true
} else {
return false
}
}
Now this function:
write error to where the caller specified in ourError should error occur
return wheter the data is valid JSON as NSDictionary
FYI I happened to write a JSON handler, too.
https://github.com/dankogai/swift-json/
Which includes NSJSONSerialization.JSONObjectWithData.

Related

I need help Debugging/Fixing this code, by the way this is in Xcode, I am using the OpenAI Package by adamrushy

I am having an issue, I don't know if it related to the package but it probably is so here is my code. This is the package I used; https://github.com/adamrushy/OpenAISwift
// Send query to OpenAI
openAI.send(prompt: query) { [weak self] (response, error) in
guard let self = self else { return }
if let error = error {
print("Error: \(error.localizedDescription)")
self.startListening()
return
}
if let response = response {
// Use Text to Speech to speak response
let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: response.text)
synthesizer.speak(utterance)
}
By the way the below Bugs are on this line "openAI.send(prompt: query) { [weak self] (response, error) in"
Bug 1: Unable to infer type of closure parameter 'error' in the current context
Bug 2: Unable to infer type of a closure parameter 'response' in the current context
Bug 3: Value of type 'OpenAI' has no member 'send'
I tried removing the error thing itself, it gave more issues. I tried changing 'send' to other things, it just kept giving the same error. And I could not touch 'response' as it is important.

How to report custom Go error types to Sentry?

I want my custom error to show up in Sentry, but it just grabs the underlying errorString type.
Is there a way to show operationTimeoutError instead?
Here's what I do:
type operationTimeoutError error
var errOperationTimeout operationTimeoutError = errors.New("TIMEOUT")
func foo() {
sentry.CaptureException(errOperationTimeout)
}
sentry will call the Error() method in the error you provided, which in return prints the error message of the underlying error. you can either override the Error method for the custom error type or map it to a new error with the message you intend to see in sentry. Since its likely that you are using the error for other purposes like logging, I think mapping is the better choice.
func mapError(err error)error{
switch err.(type){
case operationTimeoutError:
return errors.New("operationTimeoutError")
default:
return err
}
}
sentry.CaptureException(mapError(errOperationTimeout))

Generic parameter 'Element' could not be inferred?

"Generic parameter 'Element' could not be inferred" - this error comes as I write guard statement - what is inside guard statement which causes error that element could not be inferred.
static func makeTokenForCard(with cardinfo: CardInfo) -> Single<String> {
return Single.create {
single in guard let ck = try CheckoutKit.getInstance("pk_123456789876543234567, env: Environment.SANDBOX, debug: true)
else {
let descr = "Unexpectedly Checkout got invalid private key. You may need to update the app."
single(.error(NSError.recreate(error: CheckoutError.invalidPK as NSError, description: descr)))
return
}
single(.success("123456"))
return Disposables.create()
}
}
When I remove this Guard statement - it returns simple String and errors in Single.
Edit :
After getting more into error, I found that its due to throws.
open class func getInstance(_ pk: String, env: Environment, debug: Bool) throws -> CheckoutKit? {
In Simple Guard & wrapping its fine.
So, How to call a method in Single when it has throws some expected error
?
This isn't RxSwift related but more Swift and handling errors.
The simplest answer to your question is to use try? instead try. This will fix the issue.
You can read more about error handling here https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html

do-try-catch usage in Swift 2

Is this usage not correct? why? The file name I use is correct!
on the right side of the playground I would aspect to see the content of the txt file.
In terms of why this failed, you'd have to look at the error object and examine why it failed. You're catching the error, so look at it:
func read(path: String) throws {
do {
try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
} catch {
print("cannot read: \(error)")
}
}
That will tell you why it failed.
Having said all of that, this doesn't quite make sense: First, you're reading the contents of the path into the NSString, but discarding it. You presumably want to return this string or do something with it.
Second, read has been declared in such a way as to say that it throws error, but it doesn't really. It catches any error that might happen itself, but doesn't throw anything. You have to decide whether read will throw any errors it generates, or whether it will handle them without throwing any error, or both.
Assuming the caller was going to handle the error, you might just forego any do-try-catch construct in read altogether:
func read(path: String) throws -> NSString? {
return try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
}
Then you can let the caller catch any error that NSString threw. For example, you might catch the "not found" error:
do {
let string = try read(path)
// do something with string
} catch let error as NSError where error.domain == NSCocoaErrorDomain && error.code == NSCocoaError.FileReadNoSuchFileError.rawValue {
// not found handling here
} catch {
print(error)
}
If you really wanted read to not only catch the error, but also make sure it throws one as well, then you'd need to have to explicitly throw an error from its catch block. You can use this pattern using either your own ErrorType or just throwing the original error you just caught:
func read(path: String) throws -> NSString? {
var string: NSString?
do {
string = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
} catch {
// do whatever special handling you want here
// but also throw error so caller is informed that there was an issue
throw error
}
return string
}
Frankly, I think the pattern outlined above is simpler, but given your code snippet, I thought I'd also illustrate this latter pattern, too, in case you needed something like that.
I am also learning, so I wrote a little demo. Hope it helps.

Swift 2: Can't call createDirectoryAtUrl with definition

I am currently developing an application on xCode7 beta 2 using Swift 2 (it is a requirement at the moment).
Here is what I am trying to call:
let fileManager = NSFileManager.defaultManager()
let tempDirectoryURL = NSURL(string: NSTemporaryDirectory())!
let directoryURL = tempDirectoryURL.URLByAppendingPathComponent("com.test.manager/multipart.form.data")
var error: NSError?
if fileManager.createDirectoryAtURL(directoryURL, createIntermediates: true, attributes: nil) {
...
}
Here is the error I am getting:
Cannot invoke 'createDirectoryAtURL' with an argument list of type
'(NSURL, createIntermediates: Bool, attributes: nil)'
Which is confusing because the definition for createDirectoryAtURL I am getting when I right click and "view definition" is:
func createDirectoryAtURL(
url: NSURL,
withIntermediateDirectories createIntermediates: Bool,
attributes: [String : AnyObject]?
) throws
The only only paramater that doesn't match verbatim is the last parameter "attributes", which the documentation (and all example usage) explicitly states can accept the value nil.
Apple's Documentation:
If you specify nil for this parameter, the directory is created
according to the umask(2) Mac OS X Developer Tools Manual Page of the
process.
Two problems here:
You've switched an parameter label for its internal name. The second parameter's label — part of the function name, required for calling it — is withIntermediateDirectories. The implementor of that function refers to that parameter's value as createIntermediates. So your call should look like this:
fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
Note the signature you quoted:
func createDirectoryAtURL( ... ) throws
You're using this call as the condition of an if statement — that means you need a function that returns Bool. The compiler is trying to satisfy the requirement of the if statement by looking for a function called createDirectoryAtURL whose type signature is (NSURL, Bool, [String : AnyObject]?) -> Bool, and complaining because it only sees one whose signature is (NSURL, Bool, [String : AnyObject]?) throws -> Void.
The error handling system in Swift 2 takes ObjC methods that return BOOL and have an NSError out parameter and turns them into throwing methods with no return type (that is, they return Void). So, if you're looking at Swift 1.x code that uses such methods, or porting ObjC code, you need to change patterns like the following:
var error: NSError?
if fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil, error: &error) {
// all good
} else {
// handle error
}
And use patterns like this instead:
do {
try fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
// if here, all is good
} catch {
// handle error
}

Resources