I'm new to swift. I am trying to create a call to Google's API to convert any inputted addresses to a long, lat location on google maps, using their sdk.
I thought it'd be easier to start by following a tutorial http://www.appcoda.com/google-maps-api-tutorial/, then dissecting it. But I cannot seem to get it this particular line working. It will come out with a "error-exc-bad-instruction-code-exc-i386-invop-subcode-0x0" on the dicitonary line. I read other sample work on reverse geocoding that are to date, and they look very similar, but none are working. What am I doing wrong?
let dictionary: Dictionary<NSObject, AnyObject> =
NSJSONSerialization.JSONObjectWithData(geocodingResultsData!, options:
NSJSONReadingOptions.MutableContainers, error: &error) as!
Dictionary<NSObject, AnyObject>
Full function below:
func geocodeAddress(address: String!, withCompletionHandler completionHandler: ((status: String, success: Bool) -> Void)) {
if let lookupAddress = address {
var geocodeURLString = baseURLGeocode + "address=" + lookupAddress
geocodeURLString = geocodeURLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let geocodeURL = NSURL(string: geocodeURLString)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let geocodingResultsData = NSData(contentsOfURL: geocodeURL!)
var error: NSError?
let dictionary: Dictionary<NSObject, AnyObject> = NSJSONSerialization.JSONObjectWithData(geocodingResultsData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! Dictionary<NSObject, AnyObject>
// let dictionary: Dictionary = NSJSONSerialization.JSONObjectWithData(geocodingResultsData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! Dictionary
if (error != nil) {
println(error)
completionHandler(status: "", success: false)
}
else {
// Get the response status.
let status = dictionary["status"] as! String
if status == "OK" {
let allResults = dictionary["results"] as! Array<Dictionary<NSObject, AnyObject>>
self.lookupAddressResults = allResults[0]
// Keep the most important values.
self.fetchedFormattedAddress = self.lookupAddressResults["formatted_address"] as! String
let geometry = self.lookupAddressResults["geometry"] as! Dictionary<NSObject, AnyObject>
self.fetchedAddressLongitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lng"] as! NSNumber).doubleValue
self.fetchedAddressLatitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lat"] as! NSNumber).doubleValue
completionHandler(status: status, success: true)
}
else {
completionHandler(status: status, success: false)
}
}
})
}
else {
completionHandler(status: "No valid address.", success: false)
}
}
For Swift 2, this can be used:
First, declare your variable as an empty dictionary outside of the do-catch block and do the assignment in the block, like below
do {
dictionary = try NSJSONSerialization.JSONObjectWithData(geocodingResultsData!, options: NSJSONReadingOptions.MutableContainers) as! Dictionary<NSObject, AnyObject>
} catch {
//something
}
Related
I am currently trying to download, parse and print JSON from an URL.
So far I got to this point:
1) A class (JSONImport.swift), which handles my import:
var data = NSMutableData();
let url = NSURL(string:"http://headers.jsontest.com");
var session = NSURLSession.sharedSession();
var jsonError:NSError?;
var response : NSURLResponse?;
func startConnection(){
let task:NSURLSessionDataTask = session.dataTaskWithURL(url!, completionHandler:apiHandler)
task.resume();
self.apiHandler(data,response: response,error: jsonError);
}
func apiHandler(data:NSData?, response:NSURLResponse?, error:NSError?)
{
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
catch{
print("API error: \(error)");
}
}
My problem is, that the data in
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
remains empty.
When I debug,the connection starts successfully, with the given url as a parameter. But my jsonData variable doesn't get printed. Instead the catch block throws the error, stating that there is no data in my variable:
API error: Error Domain=NSCocoaErrorDomain Code=3840 "No value."
Can someone please help me with this?
What am I missing?
Thank you all very much in advance!
[Edited after switching from NSURL Connection to NSURLSession]
Here's an example on how to use NSURLSession with a very convenient "completion handler".
This function contains the network call and has the "completion handler" (a callback for when the data will be available):
func getDataFrom(urlString: String, completion: (data: NSData)->()) {
if let url = NSURL(string: urlString) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) in
// print(response)
if let data = data {
completion(data: data)
} else {
print(error?.localizedDescription)
}
}
task.resume()
} else {
// URL is invalid
}
}
You can use it like this, inside a new function, with a "trailing closure":
func apiManager() {
getDataFrom("http://headers.jsontest.com") { (data) in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let jsonDict = json as? NSDictionary {
print(jsonDict)
} else {
// JSON data wasn't a dictionary
}
}
catch let error as NSError {
print("API error: \(error.debugDescription)")
}
}
}
I cannot figure out why im getting this error.
This is the function to update a guest(Participant). I'm trying to save the Qr code i created to a PFFile and save to parse.
func update() {
_ = LabelText
let query = PFQuery(className: "Participant")
query.getObjectInBackgroundWithId(LabelText) {
(Update: PFObject?, error: NSError?) -> Void in
Update!["firstname"] = self.firstnameTF!.text
Update!["lastname"] = self.lastnameTF!.text
Update!["grade"] = self.gradeTF!.text
Update!["teacher"] = self.teacherTF.text
Update!["email"] = self.emailTF.text
Update!["phone"] = self.phoneTF.text
Update!["transportation"] = self.transportationTF.text
Update!.saveInBackground()
print("updated")
if self.QrImage == nil {
print("Image is Blank")
return
}else{
//Image is not blank
let imageData = UIImageJPEGRepresentation(self.QrImage!, 1)
let parseImageFile = PFFile(data: imageData!)
Update!.setObject(parseImageFile!, forKey: "qrcode")
Update!.saveInBackgroundWithBlock( {
(success: Bool , error: NSError?) -> Void in
})
}
self.dismissViewControllerAnimated(true, completion: {});
}
}
I can see the image in the self.QrImage field and i only get the error on:
let parseImageFile = PFFile(data: imageData!)
Why am i getting a nil error when it should have a value there?
Edit 1:
let imageData = UIImagePNGRepresentation(self.QrImage!)
let parseImageFile = PFFile(data: imageData!)
Update!.setObject(parseImageFile!, forKey: "qrcode")
Update!.saveInBackgroundWithBlock( {
(success: Bool , error: NSError?) -> Void in
})
}
Same result."fatal error: unexpectedly found nil while unwrapping an Optional value"
Edit 2:
So it seems there must be a name value associated with the image before you upload it to parse. My Image is of a Qrcode i create from other data. here's my code:
func displayQrCode() {
print(self.qrdata.text)
let data = self.qrdata.text!.dataUsingEncoding(NSISOLatin1StringEncoding)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter!.setValue(data, forKey: "inputMessage")
filter!.setValue("Q", forKey: "inputCorrectionLevel")
self.qrcodeImage = filter!.outputImage!
let scaleX = qrCode.frame.size.width / qrcodeImage!.extent.size.width
let scaleY = qrCode.frame.size.height / qrcodeImage!.extent.size.height
let transformedImage = qrcodeImage!.imageByApplyingTransform(CGAffineTransformMakeScale(scaleX, scaleY))
self.qrCode.image = UIImage(CIImage: transformedImage)
print("QRCode Made")
}
now i guess i need to add a name to the self.qrCode.image?
This is what needs to be done before you use UIImagePNGRepresentation:
self.QrImage = UIImage(named: "qrcode.png")
My app works perfectly fine with iOS 8 but yesterday I upgraded to iOS 9 and Xcode 7 then my app crashes. The error message is cannot invoke 'dataTaskwithURL' with an argument list of type '(NSURL, (_, ,)throws -> Void)'. I googled it and found a similar question here but the solution didn't really work (the solution was to add the do/catch blocks around the code). Can anyone help me with mine problem? Thank you!!!
Here's my code
import UIKit
import Foundation
import CoreLocation
class GoogleDataProvider {
let apiKey = "AIzaSyCQo-clIkek87N99RVh2lmFX9Mu9QPhAtA"
let serverKey = "AIzaSyBzmv7wPFcPAe1ucy5o6dqaXnda9i9MqjE"
var photoCache = [String:UIImage]()
var placesTask = NSURLSessionDataTask()
var session: NSURLSession {
return NSURLSession.sharedSession()
}
func fetchPlacesNearCoordinate(coordinate: CLLocationCoordinate2D, radius:Double, types:[String],keyword:String, completion: (([GooglePlace]) -> Void)) -> ()
{
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=\(serverKey)&location=\(coordinate.latitude),\(coordinate.longitude)&radius=\(radius)&keyword=\(keyword)&rankby=prominence&sensor=true"
let typesString = types.count > 0 ? types.joinWithSeparator("|") : "food"
urlString += "&types=\(typesString)"
urlString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
if placesTask.taskIdentifier > 0 && placesTask.state == .Running {
placesTask.cancel()
}
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
do{
//******************Here's the line that displays error
placesTask = session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var placesArray = [GooglePlace]()
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? NSDictionary {
if let results = json["results"] as? NSArray {
for rawPlace:AnyObject in results {
let place = GooglePlace(dictionary: rawPlace as! NSDictionary, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
}
dispatch_async(dispatch_get_main_queue()) {
completion(placesArray)
}
}
}catch{
}
placesTask.resume()
}
func fetchDirectionsFrom(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D, completion: ((String?) -> Void)) -> ()
{
let urlString = "https://maps.googleapis.com/maps/api/directions/json?key=\(serverKey)&origin=\(from.latitude),\(from.longitude)&destination=\(to.latitude),\(to.longitude)&mode=walking"
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
do{
//******************************Here too ****************************
session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var encodedRoute: String?
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? [String:AnyObject] {
if let routes = json["routes"] as AnyObject? as? [AnyObject] {
if let route = routes.first as? [String : AnyObject] {
if let polyline = route["overview_polyline"] as AnyObject? as? [String : String] {
if let points = polyline["points"] as AnyObject? as? String {
encodedRoute = points
}
}
}
}
}
dispatch_async(dispatch_get_main_queue()) {
completion(encodedRoute)
}
}.resume()
}catch{
}
}
}
Sorry this is my first time posting the code style is a little bit confusing sorry about the indentation mess :)
Thanks again!!!
dataTaskWithURL:completionHandler: does not throw error.
Put do and catch inside dataTaskWithURL method.
for example:
session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var encodedRoute: String?
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? [String:AnyObject] {
if let routes = json["routes"] as AnyObject? as? [AnyObject] {
if let route = routes.first as? [String : AnyObject] {
if let polyline = route["overview_polyline"] as AnyObject? as? [String : String] {
if let points = polyline["points"] as AnyObject? as? String {
encodedRoute = points
}
}
}
}
}
} catch {
}
dispatch_async(dispatch_get_main_queue()) {
completion(encodedRoute)
}
}.resume()
I just updated to Xcode7 and am trying to switch my project to using the Swift 2.0 Syntax when I ran into this error in a file from an open source library I'm using. Here's the relevant code:
public lazy var cookies:[String:NSHTTPCookie] = {
let foundCookies: [NSHTTPCookie]
if let responseHeaders = (self.response as? NSHTTPURLResponse)?.allHeaderFields {
foundCookies = NSHTTPCookie.cookiesWithResponseHeaderFields(responseHeaders, forURL:NSURL(string:"")!) as! [NSHTTPCookie]
} else {
foundCookies = []
}
var result:[String:NSHTTPCookie] = [:]
for cookie in foundCookies {
result[cookie.name] = cookie
}
return result
}()
The error reads: Cannot assign a value of type '[NSHTTPCookie]' to a value of type '[NSHTTPCookie]'
Is there something I'm missing here?
Change your code to this:
public lazy var cookies:[String:NSHTTPCookie] = {
let foundCookies: [NSHTTPCookie]
if let responseHeaders = (self.response as? NSHTTPURLResponse)?.allHeaderFields as? [String:String] {
foundCookies = NSHTTPCookie.cookiesWithResponseHeaderFields(responseHeaders, forURL:NSURL(string:"")!)
} else {
foundCookies = []
}
var result:[String:NSHTTPCookie] = [:]
for cookie in foundCookies {
result[cookie.name] = cookie
}
return result
}()
Changes:
if let responseHeaders ... line - did add as? [String:String], because allHeadersFields return type is [NSObject : AnyObject] and not [String:String] required by cookiesWithResponseHeaderFields...
removed as! [NSHTTPCookie] - it has no sense, because cookiesWithResponseHeaderFields return type is already [NSHTTPCookie]
Just check cookiesWithResponseHeaderFields signature:
class func cookiesWithResponseHeaderFields(headerFields: [String : String],
forURL URL: NSURL) -> [NSHTTPCookie]
Please read How do I ask a good question. At least, you should point out to lines where the problem is, etc.
I am trying to access an api using the following code.
I am getting the error "fatal error: unexpectedly found nil while unwrapping an Optional value" when I am trying to parse json.
I am not sure why is that error happening.
The data is not nil.
var urlFull = NSURL(string: url)!
var urlrequest = NSURLRequest(URL: urlFull)
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(urlrequest, queue: queue, completionHandler: {
(response, data, error) -> Void in
println(response)
println(data)
println(error)
if let anError = error {
println(error)
} else {
var jsonError: NSError? = nil
let post = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as NSDictionary
if let aJSONError = jsonError {
println("Error parsing")
} else {
println("The post is: " + post.description)
}
}
})
The problem is your forced cast: as NSDictionary. Whatever's being returned can't be casted to NSDictionary.
You should always use optional casting (as?) and optional unwrapping (if let…) when parsing JSON:
let post = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as? NSDictionary
if let post = post {
// it worked! parse post
} else {
// it's not a dictionary.
println(post)
// see what you have and debug from there
}