Do - Catch error handling Swift 2.0 - swift

I have read through numerous posts regarding conversion between older versions of swift and swift 2.0 on the issue of Do-catch error handling. However each and every one of them seem different to my personal issue.
Besides solving my personal issue I'm fairly curious as to what the general idea is behind this concept, because I simply can not figure out how this works on a low level scale just by reading all these topics.
I'll post my personal issue below, but I'd also very much appreciate some sort of general explanation about how this do-catch method works.
if(urlResponse.statusCode == 200) {
self.tweets = NSJSONSerialization.JSONObjectWithData(responseData,
options: NSJSONReadingOptions.MutableContainers,
error: &jsonParseError) as? NSMutableArray
}
the error shows at the line:
error: &jsonParseError) as? NSMutableArray

Change your code to
if(urlResponse.statusCode == 200) {
do {
self.tweets = try NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.MutableContainers) as? NSMutableArray
} catch let jsonParseError {
print("Parse error = \(jsonParseError)")
}
}
You can find more about error handling here.

Related

Can't populate empty dictionary in Swift

I am trying to build a flutter plugin for the Sendbird iOS SDK. For some reason whenever I try to fetch data, I get null from a NSDictionary<NSString *,NSObject *> when I know for a fact that it is not (I have created the keys and values separately).
Most likely it's the fact that being a beginner with Swift I am doing something wrong. This is my code:
let channelMetadata = NSMutableDictionary()
// metadata is the NSDictionary<NSString *,NSObject *>
channel.getAllMetaData{ (metaData, error) in
guard let metadata = metaData, error == nil else {
// Error.
return
}
channelMetadata["status"] = metadata["status"]
channelMetadata["type"] = metadata["type"]
}
js["status"] = channelMetadata["status"]
it's:
js["status"]
Which returns null. I assume this is because I am doing something wrong with the way I am populating my empty dictionary, but I don't know what, even after searching for hours. Any help would be really appreciated.

Understanding error handling with CoreData

I have a scenario where I expect something to happen, but it does not and I can't seem to figure out why. I am still new with throwing functions, so I am a bit curious here. Maybe someone can explain why this happen.
I have made this function:
func checkExistanceOfMovieAddition(id: Int) -> Result<SavedMovieAddition, CoreDataErrors> {
let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: SavedMovieAddition.entityName)
request.predicate = NSPredicate(format: "movieID == \(id)")
do {
let fetch = try context.fetch(request)
if let result = fetch.first as? SavedMovieAddition {
return.success(result)
} else {
return.failure(.additionNotFound)
}
} catch {
return.failure(.fetchFailed)
}
}
And it works like a charm. If I search for an id that does not exist I get an empty array and return my custom error type. However.. if I change the line:
request.predicate = NSPredicate(format: "movieID == \(id)")
and misspell "movieID" with "movieIDs" which does not exists in my CoreData model the app crashes with:
Thread 1: Exception: "keypath movieIDs not found in entity <NSSQLEntity SavedMovieAddition id=2>"
Here I would expect it to go the the catch block and return .fetchFailed?
Why is this not happening? But instead the app is crashing? - I thought the whole point of have a do-try-catch block was to eliminate these crashes?
Is there something I am missing?
You've had some comments with good explanations. One more thing that may be useful is that you can help to avoid the kind of error you describe by not using bare strings if you can avoid them. When possible, do something that will let the compiler check whether you've misspelled something. In this case, Swift keypaths would help.
You have
request.predicate = NSPredicate(format: "movieID == \(id)")
...which works but is a problem if you misspell the property. If you write this as
request.predicate = `NSPredicate(format: "\(#keyPath(SavedMovieAddition.movieID)) == \(id)")`
...the key path would be checked by the compiler. If you typed it as movieIDs, your code wouldn't compile and you'd get an error saying that Type 'SavedMovieAddition' has no member 'movieIDs'. You could also write it this way, if it makes more sense to you:
request.predicate = `NSPredicate(format: "%K == \(id)", #keyPath(SavedMovieAddition.movieID))`

Swift 3 Completion Handler on Google Places Lookup. Due to delay how do I know when Im "done"?

Sorry, newbie here and Ive read extensively about completion handlers, dispatch queues and groups but I just can't get my head around this.
My app loads an array of Google Place IDs and then wants to query Google to get full details on each place. The problem is, due to async processing the Google Lookup Place returns immediately and the callback happens much further down the line so whats the "proper way" to know when the last bit of data has come in for my inquiries because the function ends almost immedately ?
Code is attached. Thanks in advance.
func testFunc() {
let googlePlaceIDs = ["ChIJ5fTXDP8MK4cRjIKzek6L6NM", "ChIJ9Wd6mGYGK4cRiWd0_bkohHg", "ChIJaeXT08ASK4cRkCGpGgzYpu8", "ChIJkRkS4BapK4cRXCT8-SJxNDI", "ChIJ3wDV_2zX5IkRtd0hg2i1LhE", "ChIJb4wUsI5w44kRnERe7ywQaJA"]
let placesClient = GMSPlacesClient()
for placeID in googlePlaceIDs {
placesClient.lookUpPlaceID(placeID, callback: { (place, error) in
if let error = error {
print("lookup place id query error: \(error.localizedDescription)")
return
}
guard let place = place else {
print("No place details for \(placeID)")
return
}
print("Place Name = \(place.name)")
})
}
print("Done")
}

Proper Use of the Swift Guard Keyword?

I've been looking up how to use the guard keyword in Swift. Recently a developer told me that the code below will print "success" if there's no error in the closure.
for attachment in attachments! {
attachment.fetchData { (data, error) in
guard let error = error else {
print(“success”)
return
}
print(error.localizedDescription)
}
I'm a bit confused by his statement. After reading the closure and guard keyword documentation from Apple, it looks to me like his code will print out "success" only when there is an error.
I feel like he's using it in reverse, but I may be wrong. Can someone break it down for me and explain if success is printed when there is or is not an error?
Thank you.
The use of guard to unwrap the error is very misleading. You should use it to unwrap your data and make sure there is no error and provide an early exit to your method in case of error.
Just change your guard statement to:
guard let data = data, error == nil else {
print(error ?? "")
return
}

Error : Command failed due to signal : Segmentation fault: 11

I am trying to get an array from dictionary, but I am getting an error for below line
self.items = self.dataDictionary["geoNames"] as NSArray
Complete code is as below
var dataDictionary: AnyObject!
var items: NSArray!
override func viewDidLoad() {
super.viewDidLoad()
var url = NSURL(string: "http://api.geonames.org/countryInfoJSON?username=temp")
var urlRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue:NSOperationQueue(), completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if (data.length > 0 && error == nil){
self.dataDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
println(self.dataDictionary)
self.items = self.dataDictionary["geoNames"] as NSArray
}
})
}
A Hypothesis: If the editor is - for some reason - unable to parse through your code and make conclusions about the correctness of your code, it might allow you to compile even if you have syntax errors, which might lead to the error you describe.
I was getting this error because of syntax errors. Namely, I was changing a 1D array to a 2D array, but had forgotten to update some of the places it is initialized.
It seems that the editor was unable to pinpoint exactly where the errors were and when I tried compiling, I got the error you are describing. I suspected something funky was going on with the editor because it was flashing between all-white and colored syntax, and throwing the "An internal error happened" error message at the top of the editor.
So if you have this error, manually double-checking your code or undoing your changes one by one until you get to a stage where you can compile successfully might give you a hint of what's going wrong.
Posting because it might be helpful to someone facing a similar issue.
I had the same error with a cocoapod install and noticed my Foundation.framework stop being recognized. Take a look at my answer here on this thread which solved my problem. Hope this helps someone.
In the event you don't want to visit the link, simply run
sudo gem install cocoapods
to update the pods if you suspect your outdated cocoa pods are giving you trouble with the frameworks
There are a few problems with your code:
Your code does not even compile. Segfault is coming from the compiler, not at runtime
You should cast the result from JSONObjectWithData as
NSDictionary, not assign to a variable of type AnyObject!
Should use if to check if the casting works
The dictionary key is wrong. It is geonames (all lowercase)
Here is the functional code:
var url = NSURL(string: "http://api.geonames.org/countryInfoJSON?username=temp")
var urlRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue:NSOperationQueue(), completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if (data.length > 0 && error == nil){
if let jsonObject = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary {
let dataDictionary = jsonObject["geonames"]
println(dataDictionary)
}
}
})
This happened to me because I incorectly created an if statement. Very very simple error, I just missed one key, but caused a world a difference.:
if textBox?.characters.count = 0{
//...
}
instead I needed to do:
if textBox?.characters.count == 0{
//...
}