Trying to fetch image URL in Swift using Google Image API - json

I'm trying to use the google image API with JSON (https://developers.google.com/image-search/v1/jsondevguide) to get the URL of the first image that shows when searching something. This is what I have:
let placeName = "New York"
func getImage() {
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=\(placeName)")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){ (response, go, error) -> Void in
let go = NSJSONSerialization.JSONObjectWithData(go, options: NSJSONReadingOptions.AllowFragments, error: nil) as [String:AnyObject]
let responseData = go["responseData"] as [String:AnyObject]
// let results = responseData["results"] as [String:AnyObject]
// let imageURL = results["unescapedUrl"] as String
println(responseData)
}
}
The responseData part is as far as I can go (that then returns everything), but trying to go one level deeper (to "results") will crash it.

You declare results as a dictionary but your linked Google page shows an example where results is an array of dictionaries.
You can do this instead:
let results = responseData["results"] as [[String:String]]
let firstObject = results[0]
let firstURL = firstObject["unescapedUrl"]

Related

Swift, making custom MapKit annotations with json/php

I'm following this tutorial: https://www.raywenderlich.com/160517/mapkit-tutorial-getting-started
These questions are in regard to swift (whatever the latest version of xcode uses), JSON and PHP. The tutorial works as is, but I want to make several modifications. I've done everything else but I'm stuck on the following questions.
There are several differences between the tutorial code and what I'm trying to get the app to do. Mainly, the JSON format in the tutorial is different from what my PHP page is spitting out.
I have several questions.
1) How do I modify the code to:
a) use the JSON data from a URL, not from the PublicArt.json file as used in the tutorial, and
b) how do I modify the code from the tutorial to accept the JSON format I'm receiving from a PHP file on my server?
The above question is in reference to the following 2 piece of code (original code in the tutorial):
init?(json: [Any]) {
// 1
self.title = json[16] as? String ?? "No Title"
self.locationName = json[12] as! String
self.discipline = json[15] as! String
// 2
if let latitude = Double(json[18] as! String),
let longitude = Double(json[19] as! String) {
self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
} else {
self.coordinate = CLLocationCoordinate2D()
}
}
and this code (original code in the tutorial):
func loadInitialData() {
// 1
guard let fileName = Bundle.main.path(forResource: "PublicArt", ofType: "json")
else { return }
let optionalData = try? Data(contentsOf: URL(fileURLWithPath: fileName))
guard
let data = optionalData,
// 2
let json = try? JSONSerialization.jsonObject(with: data),
// 3
let dictionary = json as? [String: Any],
// 4
let works = dictionary["data"] as? [[Any]]
else { return }
// 5
let validWorks = works.flatMap { Artwork(json: $0) }
artworks.append(contentsOf: validWorks)
}
The JSON format used in the tutorial is this:
[ 55, "8492E480-43E9-4683-927F-0E82F3E1A024", 55, 1340413921, "436621", 1340413921, "436621", "{\n}", "Sean Browne", "Gift of the Oahu Kanyaku Imin Centennial Committee", "1989", "Large than life-size bronze figure of King David Kalakaua mounted on a granite pedestal. Located at Waikiki Gateway Park.", "Waikiki Gateway Park", "http://hiculturearts.pastperfect-online.com/34250images/002/199103-3.JPG", "1991.03", "Sculpture", "King David Kalakaua", "Full", "21.283921", "-157.831661", [ null, "21.283921", "-157.831661", null, false ], null ]
The format from my PHP file that I want to use is this:
{"id":1,"placeid":"1","lat":"25.4432","long":"-153.2345","location_title":"Sample Location","location_subtitle":"Sample Subtitle","log_status":"success"}
{"id":2,"placeid":"2","lat":"25.4543","long":"-153.2345","location_title":"Sample Location 2","location_subtitle":"Sample Subtitle 2","log_status":"success"}
{"id":3,"placeid":"3","lat":"25.4632","long":"-153.2345","location_title":"Sample Location 3","location_subtitle":"Sample Subtitle 3","log_status":"success"}
The tutorial uses file PublicArt.json and I use url htttp//www.samplesite.com/json.php (not really the url I use but you get it, the url I actually use produces working JSON code)
2) Finally, the tutorial uses a callout accessory as an info button to open up the Maps app to give directions to a location. Instead, how can I use this button to create a segue to a different ViewController when the button is clicked? I think this is the part of the code from the tutorial the opens the Maps app:
let mapsButton = UIButton(frame: CGRect(origin: CGPoint.zero,
size: CGSize(width: 30, height: 30)))
mapsButton.setBackgroundImage(UIImage(named: "Maps-icon"), for: UIControlState())
rightCalloutAccessoryView = mapsButton
Thanks for your help. It's very appreciated!
Edit:
Ok, so here's my code for getting information from "my PHP file". In this case you don't even need var1 and var2, because json.php is made to spit out all the data anyway. With my code I can just us responseJSON["whatever"] to get values out of the response string. I'm confused about the formatting in the tutorial.
let url = "https://www.samplesite.com/json.php"
let var1 = self.textForm1.text!
let var2 = self.textForm2.text!
let request = NSMutableURLRequest(url: NSURL(string: url)! as URL)
request.httpMethod = "POST"
let postString = "var=\(var1)&var2=\(var2)"
print(postString)
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
guard error == nil && data != nil else {
print("error=\(String(describing: error))")
return
}
do {
if let responseJSON = try JSONSerialization.jsonObject(with: data!) as? [String:AnyObject]{
// If successful
if ((responseJSON["log_status"]!) as! String == "success") {
// do stuff here if log_status response is success
}
} else {
//If there is an error do stuff here
}
}
}
catch {
print("Error -> \(error)")
}
}
task.resume()
How do I modify the code from the tutorial to be able to parse the data in a similar way? This is the code from the tutorial:
func loadInitialData() {
// 1
guard let fileName = Bundle.main.path(forResource: "PublicArt", ofType: "json")
else { return }
let optionalData = try? Data(contentsOf: URL(fileURLWithPath: fileName))
guard
let data = optionalData,
// 2
let json = try? JSONSerialization.jsonObject(with: data),
// 3
let dictionary = json as? [String: Any],
// 4
let works = dictionary["data"] as? [[Any]]
else { return }
// 5
let validWorks = works.flatMap { Artwork(json: $0) }
artworks.append(contentsOf: validWorks)
}

Swift - Parsing JSON and retrieve data

I am working with Swift on Xcode and I try to parse a JSON file to retrieve some data about nearby stores.
My source code is the following:
import GooglePlaces
import SwiftyJSON
class Place {
let name: String
let coordinates: CLLocationCoordinate2D
init(diction:[String : Any])
{
let json = JSON(diction)
name = json["name"].stringValue //as! String
let lat = json["geometry"]["location"]["lat"].doubleValue as CLLocationDegrees
let long = json["geometry"]["location"]["lng"].doubleValue as CLLocationDegrees
coordinates = CLLocationCoordinate2DMake(lat, long)
}
}
class ViewController: UIViewController, MKMapViewDelegate, SceneLocationViewDelegate {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
urlString += "&location=51.507514,-0.073603"
urlString += "&radius=1500" //meters
urlString += "&name=Specsavers"
urlString += "&key=**************************"
guard let url = URL(string: urlString) else {return}
var places = [Place]()
var request = URLRequest(url:url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
print("HEREurlSession")
if let content = data {
do {
let json = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(json) // json results are printed fine here
if let results = json["results"] as? [[String : Any]] {
for place in results {
places.append(Place(diction: place))
}
}
else {
print("return")
}
}
catch{
}
}
}
task.resume()
let size = places.count
print("HERE: ", size)
}
The build is successful but the output is size = 0 which means that I do not retrieve the data and the variable places is empty.
I do not know if it is exactly relevant but I get the following warning: Cast from 'MDLMaterialProperty?!' to unrelated type '[[String : Any]]' always fails for the line if let results = json["results"] as? [[String : Any]] in my source code.
Why I do not parse the JSON file correctly and I do not retrieve the data the I want to?
URLSession.shared.dataTask(with:) is asynchronous. This means, it runs in the background. You are executing
let size = places.count
print("HERE: ", size)
while the dataTask is still working.
Instead, you should use your result in the completion handler:
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
print("HEREurlSession")
if let content = data {
do {
let json = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(json)
if let results = json["results"] as? [[String : Any]] {
for place in results {
places.append(Place(diction: place))
}
}
else {
print("return")
}
}
catch{
}
}
// Use your result here
let size = places.count
useResultSize(size)
}
task.resume()
func useResultSize(_ size: Int) {
// Use your result here
print("HERE: ", size)
}
UPDATE
It seems, that you are missing what asynchronous execution actually means. Let me try to explain.
Lets mark the execution order in the code:
First, the red parts of your code are executed. Program execution starts at the top, then moves to the bottom red box and only after that (once the network request is finished) the green part is executed.
That means, that you can only use the result of the network request in the green part of the code. Outside of the green part, the result is not guaranteed to be available.
If you follow my initial advice, than everything should work. Please see the successful execution in my playground:

swift - unexpectedly found nil while unwrapping an Optional value when searching in Google Images

let placeName = "New York"
func getImage(place: String) {
let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=\(place)")
let request = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){ (response, go, error) -> Void in
do {
let go = try NSJSONSerialization.JSONObjectWithData(go!, options: NSJSONReadingOptions.AllowFragments) as! [String:AnyObject]
let responseData = go["responseData"] as! [String:AnyObject]
let results = responseData["results"] as! [[String:String]]
let firstObject = results[0]
let firstURL = firstObject["unescapedUrl"]
print(responseData)
} catch{
print(error)
}
}
}
getImage(placeName)
It looks like when I want to grab an image from Google Images, it won't work. Can someone please figure out what I am doing wrong?
Your URL is badly formatted. Delete the space between New and York.

How to parse the data from JSON iOS

I am building an app in iOS using SWIFT and i have also been using swiftyJSON to make this project a little easier.
func parseJSON(){
let path : String = NSBundle.mainBundle().pathForResource("jsonFile", ofType: "json") as String!
let url : String = "http://www.thegoodsite.org/attend/api.php?users_id=1"
let nsurly = NSURL(string: url)
let jsonData = NSData(contentsOfURL: nsurly!) as NSData!
let readableJSON = JSON(data: jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
var Name = readableJSON
numberOfRows = readableJSON["People"].count //Ignore this for the question
NSLog("\(Name)")
}
I am loading this data from a url so if going to include a picuture of the data im getting back in the console.
CLICK THIS LINK TO SEE IMAGE OF WHAT THE CONSOLE SAYS
So what code do i need to add to get the email to come out as text.
var Name = readableJSON ["users","email"]
However when I do that to the code I seems not to get any data at all.
How can I edit this code to get the email like I want?
let users = readableJSON["users"]
let user = users[0] // get info of the first user, you should check more here
let email = user["email"]
Or (as #nhgrif's cmt):
if let users = readableJSON["users"], user = users.first, email = user["email"]
I play the code,then i found the result of Json if Dictionary, so use the var Name = readableJSON["users"]!![0]["email"]

How parse json in tableview using swift?

I am trying to read json date from url and parse it in Tableview using swift. how can I make variable "jsonResult " as global ?
or please guide me how can I populate the tableview with this data from json.
let urlPath = "http://omanevents.net/OmanEventsApp/testPullDate.php"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if (error != nil) {
println("error")
}else {
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
for var index = 0; index < jsonResult["Events"]?.count ; ++index {
println(jsonResult["Events"]?[index]["Location"])
}
}
})
task.resume()
I would highly recommend that you have a look at this tutorial.
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
It shows you how to deal with core data but in the example it uses adding things to tableView, and saving data for use of the app at later stages. Ray Wnderlich is a great website.