So I have a problem where I call save after putting some items in an object. I go to an API and I download some info and then I save it to another system for temporary use, however the .save() seems to only save 2 items, with no special pattern in which it selects. Can someone explain what the problem is?
let url = URL(string: link)
let spots = PFObject(className:"spot")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error)
}
else{
if let urlContent = data{
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
let results = (jsonResult as! NSDictionary)["results"]
let venueList = (results as! NSArray)
//print(jsonResult)
var i = 0
while i < venueList.count{
let venues = venueList[i] as! NSDictionary
let name = venues["name"] as! String
let geometry = venues["geometry"] as! NSDictionary
let location = geometry["location"] as! NSDictionary
let cLat = location["lat"] as! Double
let cLon = location["lng"] as! Double
let vPoint = PFGeoPoint(latitude: cLat, longitude: cLon)
//print(name," ", vPoint)
spots["venue"] = name
spots["name"] = vPoint
do{
try HotSpots.save()
print("Saved! ",name," ", vPoint)
}
catch{
print("Save Error")
}
i+=1
}
}
catch{
print("JSON Error")
}
}
}
}
task.resume()
}
The issue is that you're saving the two values always in the same PFObject instance.
Move the line let spots = PFObject(className:"spot") in the loop.
PS: Use Swift native types. For example this is more efficient
let location = geometry["location"] as! [String:Double]
let cLat = location["lat"]!
let cLon = location["lng"]!
Related
I am new to swift and Maps. I am facing problem with displaying user live location. I have to display user location like Uber and Ola. I am getting array of coordinates from server.
This is the way i am fetching coordinates from server. I want to show moving user location. see following my code.
func SetUpMapsUI()
{
AdminAPIManager.sharedInstance.getAdminRunningStatusFromURL(){(resignationsJson)-> Void in
let swiftyJsonVar = JSON(resignationsJson)
let status = swiftyJsonVar["status"].rawString() as! String
print("status",status)
let message = swiftyJsonVar["message"].rawString()
if status.isEqual("0"){
if (message?.isEqual("No trips done so far."))!
{
self.mapViewBottomCons.constant = 0
}else
{
self.mapViewBottomCons.constant = 70
}
self.Bottom_view.isHidden = true
Toast.short(message: message as! String)
return
}
let busVar = swiftyJsonVar["bus_details"].rawString()!
let jsonData = busVar.data(using: .utf8)!
let LocationArray = try? JSONSerialization.jsonObject(with: jsonData, options: []) as! Array< Any>
for data in LocationArray!
{
let dic = data as! NSDictionary
guard let lat = dic.value(forKey: "latitude") as? Double else {
return
}
print("latlatlatlat",lat)
guard let lon = dic.value(forKey: "longitude") as? Double else {
return
}
print("longitude",lon)
self.arrayMapPath.append(NewMapPath(lat: Double(lat), lon: Double(lon)))
}
if self.arrayMapPath.count > 0
{
self.drawPathOnMap()
}
}
here is library that does that functionality it is written for both swift and ObjC..
ARCarMovement
here is a Stackoverflow SO answer
[["The Cheesecake Factory", 3.8], ["Dave & Buster\'s", 3.8], ["Paul Martin\'s American Grill", 4.2], ["Yard House", 4.3], ["Javier\'s Restaurant - Irvine", 4], ["CUCINA enoteca Irvine", 4.4], ["SUBWAY®Restaurants", 3.2], ["SUBWAY®Restaurants", 4], ["Wendy\'s", 3.8], ["Izakaya Wasa", 3.7], ["Veggie Grill", 4.5], ["Bruegger\'s Bagels", 4.5], ["Capital Seafood Restaurant - Irvine Spectrum", 4], ["Burger King", 3.5], ["SUBWAY®Restaurants", 2.6], ["Corner Bakery Cafe", 3.9], ["Taiko Japanese Restaurant", 4.3], ["Red Robin Gourmet Burgers", 3.7], ["Johnny Rockets", 2.9], ["Chipotle Mexican Grill", 4]]
20
2017-11-15 13:26:36.367072-0800 E-Bike App[2584:1830704] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'
*** First throw call stack:
(0x183ef5d04 0x183144528 0x183e510c4 0x102debe4c 0x102cafc84 0x184480f94 0x1844983b4 0x1848c1310 0x1848019e4 0x1847f1620 0x10532545c 0x105331b74 0x10532545c 0x105331b74 0x105331a34 0x1848c2fe8 0x10532545c 0x105332800 0x10533109c 0x105336b54 0x105336880 0x183b1f120 0x183b1ec20)
libc++abi.dylib: terminating with uncaught exception of type NSException'
Once I get the place name, rating and location (CLLocationCoordinate2D) above and save in the double array and parse index and location to drawPolylineAmongMultiplePoints function to find the distance and duration and append or push to the double array. NSRangeException is keep poping up..
Anyone has good idea to solve this?
func drawPolylineAmongMultiplePoints(coordinate: CLLocationCoordinate2D, pinPoint: Int) {
guard let lat = mapView.myLocation?.coordinate.latitude else {return}
guard let long = mapView.myLocation?.coordinate.longitude else {return}
let aPointCoordinate = "\(lat),\(long)"
let bPointCoordinate = "\(coordinate.latitude),\(coordinate.longitude)"
let url = "http://maps.googleapis.com/maps/api/directions/json?origin=\(aPointCoordinate)&destination=\(bPointCoordinate)&sensor=false&mode=\(DrivingMode.DRIVING)"
guard let urlString = URL(string: url) else {
print("Error: Cannot create URL")
return
}
let urlRequest = URLRequest(url: urlString)
// Set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// Make the request
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
do{
if error != nil{
print("Error: \(String(describing: error?.localizedDescription))")
} else {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary else {
throw JSONError.ConversionFailed
}
let arrayRoutes = json["routes"] as! NSArray
let dicOfPoints = arrayRoutes[0] as! NSDictionary
let dic1 = dicOfPoints["overview_polyline"] as! NSDictionary
let points = dic1["points"] as! String
let arrayLegs = (arrayRoutes[0] as! NSDictionary).object(forKey: "legs") as! NSArray
let arraySteps = arrayLegs[0] as! NSDictionary
let dicDistance = arraySteps["distance"] as! NSDictionary
let totalDistance = dicDistance["text"] as! String
self.totalremainingDistance = (dicDistance["value"] as! Double)*(1/1000)*(1.61)
let dicDuration = arraySteps["duration"] as! NSDictionary
let totalDuration = dicDuration["text"] as! String
self.totalremainingDuration = dicDuration["value"] as! Double
let position = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude)
//self.eachCarouselDataDic[index] += [totalDistance, totalDuration]
//print(self.eachCarouselDataDic)
self.eachCarouselDataDic[pinPoint] += [totalDistance, totalDuration, points, position]
//print(self.eachCarouselDataDic)
}
}catch let error as JSONError {
print(error.rawValue)
}catch let error as NSError {
print(error.debugDescription)
}
})
task.resume()
}
#objc func POIForPlaces(sender: UIButton) {
print("I am here~~~")
//mapView.clear()
//For Carousel view to have access to the POI elements
isThisFirstTime = false
self.eachCarouselDataDic.removeAll()
var typeOfPlace = String()
var markerImage = UIImage()
switch sender.tag {
case 0:
typeOfPlace = "cafe"
markerImage = UIImage(named: "cafe")!
case 1:
typeOfPlace = "restaurant"
markerImage = UIImage(named: "restaurant")!
default:
break
}
let markerView = UIImageView(image: markerImage)
guard let lat = mapView.myLocation?.coordinate.latitude else {return}
guard let long = mapView.myLocation?.coordinate.longitude else {return}
var arrayOfLocations = [CLLocationCoordinate2D()]
arrayOfLocations.removeFirst()
var arrayOfNames = [String()]
arrayOfNames.removeFirst()
var arrayOfAddress = [String()]
arrayOfAddress.removeFirst()
var arrayOfRating = [Double()]
arrayOfRating.removeFirst()
var name = String()
var counter = 0
let jsonURLString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(lat),\(long)&maxprice=3&radius=3200&opennow&type=\(typeOfPlace)&key=\(Config.GOOGLE_API_KEY)"
guard let urlString = URL(string: jsonURLString) else {
print("Error: Cannot create URL")
return
}
//markerView.tintColor = UIColor.DTIBlue()
let urlRequest = URLRequest(url: urlString)
// Set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
guard let httpResponse = response as? HTTPURLResponse else { return }
switch httpResponse.statusCode {
case 200:
do{
guard let data = data else { return }
guard let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary else { return }
//print(json)
DispatchQueue.global(qos: .background).async {
let arrayPlaces = json["results"] as! NSArray
if arrayPlaces.count > 0 {
for i in 0..<arrayPlaces.count {
print("-----------------------------------------------------------------------------------------------------")
print(arrayPlaces.count)
print("-----------------------------------------------------------------------------------------------------")
self.eachCarouselDataDic.append([])
let arrayForLocations = (((arrayPlaces[i] as! NSDictionary).object(forKey: "geometry") as! NSDictionary).object(forKey: "location") as! NSDictionary)
let lat = arrayForLocations.object(forKey: "lat")
let long = arrayForLocations.object(forKey: "lng")
let position = CLLocationCoordinate2D(latitude: lat as! CLLocationDegrees, longitude: long as! CLLocationDegrees)
let arrayForName = (arrayPlaces[i] as! NSDictionary).object(forKey: "name") as! String
let arrayForAddress = (arrayPlaces[i] as! NSDictionary).object(forKey: "vicinity") as! String
if let arrayForRating = (arrayPlaces[i] as! NSDictionary).object(forKey: "rating") as? NSNumber {
arrayOfRating.append(Double(truncating: arrayForRating).rounded(toPlaces: 1))
self.eachCarouselDataDic[i] += [arrayForName, arrayForRating]
print(self.eachCarouselDataDic)
} else {
arrayOfRating.append(0.0)
self.eachCarouselDataDic[i] += [arrayForName,0.0]
print(self.eachCarouselDataDic)
}
print("-----------------------------------------------------------------------------------------------------")
print(self.eachCarouselDataDic.count)
print("-----------------------------------------------------------------------------------------------------")
arrayOfNames.append(arrayForName)
arrayOfAddress.append(arrayForAddress)
arrayOfLocations.append(position)
//self.eachCarouselDataDic[i] += [arrayForName,arrayForRating]
//self.drawPolylineAmongMultiplePoints(coordinate: position, index: counter)
counter += 1
let nearbyMarker = GMSMarker()
//var position = CLLocationCoordinate2D()
nearbyMarker.iconView = markerView
name = arrayOfNames[i]
nearbyMarker.tracksViewChanges = true
nearbyMarker.title = name
nearbyMarker.position = position
nearbyMarker.snippet = "Rating = \(arrayOfRating[i]) \(self.ratingSystem(rating: arrayOfRating[i]))\n Address = \(arrayOfAddress[i])"
nearbyMarker.map = self.mapView
}
}
for i in 0..<counter {
self.drawPolylineAmongMultiplePoints(coordinate: arrayOfLocations[i], pinPoint: i)
}
}
}catch let error as NSError {
print(error.debugDescription)
}
default:
print("HTTP Reponse Code: \(httpResponse.statusCode)")
}
}
task.resume()
UIView.animate(withDuration: 3, animations: {
self.isCarouselActive = true
self.myLocationButton.setImage(UIImage(named: "carousel"), for: .normal)
})
}
The error tells you the problem:
index 0 beyond bounds for empty NSArray
So you have an empty array when you don't expect one.
Use the debugger and/or print() statements to examine the values of your variables. Work back from the point of failure to discover where it goes wrong.
You really need to do this yourself, you've provided a lot of code for people to work through. If you get stuck and cannot figure out the problem all a new question, include just sufficient code to show issue, explain what you've done and can't figure out, etc. Someone will undoubtedly help you at that point.
In this order detail array i am having 10 dictionaries but i need to display only first dictionary can any one help me how to implement this ?
http://www.json-generator.com/api/json/get/bUKEESvnvS?indent=2
here is my code shown below
func downloadJsonWithURL() {
let url = NSURL(string: self.url)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
self.orderdetailsArray = (jsonObj!.value(forKey: "Orders detail") as? [[String: AnyObject]])!
for array in self.orderdetailsArray {
let key = "OrderId"
let value = "#1000501"
for (key,value) in array{
if let addressDict = array as? NSDictionary{
if let orderid = addressDict.value(forKey: "OrderId"){
self.orderid.append(orderid as! String)
}
if let orderdate = addressDict.value(forKey: "OrderDate"){
self.orderdate.append(orderdate as! String)
}
if let subtotal = addressDict.value(forKey: "SubTotal"){
self.subTotal.append(subtotal as! Int)
}
if let Shipping = addressDict.value(forKey: "Shipping"){
self.shippingPrice.append(Shipping as! Int)
}
if let tax = addressDict.value(forKey: "Tax"){
self.tax.append(tax as! Int)
}
if let grandtotal = addressDict.value(forKey: "GrandTotal"){
self.grandTotal.append(grandtotal as! Int)
}
if let shippingAddress = addressDict.value(forKey: "ShippingAddress"){
self.shippingAddress.append(shippingAddress as AnyObject)
}
if let shippingMethod = addressDict.value(forKey: "ShippingMethod"){
self.shippingMethod.append(shippingMethod as AnyObject)
}
if let billingAddress = addressDict.value(forKey: "BillingAddress"){
self.billingAddress.append(billingAddress as AnyObject)
}
if let paymentMethod = addressDict.value(forKey: "PayMentMethod"){
self.paymentMethod.append(paymentMethod as AnyObject)
}
self.itemsArray = addressDict.value(forKey: "Items detail") as! [[String : AnyObject]]
}
}
}
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
Do this. :
let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
guard let Ordersdetail = jsonObj["Orders detail"] as? [NSDictionary] else {
print("Cannot find key 'Orderdetails' in \(jsonObj)")
return
}
To access the contents of the first dictionary do this:
var orderid = Ordersdetail[0]["OrderId"]!
var shippingadress = Ordersdetail[0]["ShippingAddress"]!
var total = Ordersdetail[0]["GrandTotal"]!
var subtotal = Ordersdetail[0]["SubTotal"]!
var tax = Ordersdetail[0]["Tax"]!
var shipping = Ordersdetail[0]["Shipping"]!
Hi if you want first dictionary of that
self.orderdetailsArray
then
if let firstDictInfo = self.orderdetailsArray.first as? [String:Any] {
// Do your stuff here
print(firstDictInfo["OrderId"])
}
Instead of looping through the whole dictionary is dictionaries, you should just take the first dictionary and only parse that. There was also quite a few other conceptual problems with your code. In Swift, don't use NSDictionary, but use the native Swift version, Dictionary, which keeps the type information of its contents. Also, use conditional casting to make sure your program doesn't crash even if the received data is wrong/unexpected and don't use force unwrapping of optionals.
Also, when parsing a JSON response in Swift, in general it is not necessary and not a good idea to iterate through the key-value pairs of the dictionaries in the response. You should know what data structure you expect, otherwise you can't parse it properly and since you can directly access dictionary values in Swift if you know the key it corresponds to, there's no need to iterate through the dictionary in a loop.
func downloadJsonWithURL() {
let url = URL(string: self.url)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = (try? JSONSerialization.jsonObject(with: data!, options: .allowFragments)) as? [String:Any] {
guard let self.orderdetailsArray = jsonObj["Orders detail"] as? [[String: AnyObject]] else {return}
guard let firstOrderDetails = self.orderdetailsArray.first else {return}
let key = "OrderId"
let value = "#1000501"
if let ordered = firstOrderDetails["OrderId] as? String {
self.orderid.append(orderid)
}
if let orderdate = firstOrderDetails["OrderDate"] as? String{
self.orderdate.append(orderdate)
}
if let subtotal = firstOrderDetails["SubTotal"] as? Int{
self.subTotal.append(subtotal)
}
if let shipping = firstOrderDetails["Shipping"] as? Int{
self.shippingPrice.append(shipping)
}
if let tax = firstOrderDetails["Tax"] as? Int{
self.tax.append(tax)
}
if let grandtotal = firstOrderDetails["GrandTotal"] as? Int{
self.grandTotal.append(grandtotal)
}
if let shippingAddress = firstOrderDetails[ "ShippingAddress"] as? AnyObject{ //why don't you store it as a String?
self.shippingAddress.append(shippingAddress)
}
if let shippingMethod = firstOrderDetails[ "ShippingMethod"] as? AnyObject{
self.shippingMethod.append(shippingMethod)
}
if let billingAddress = firstOrderDetails[ "BillingAddress"] as? AnyObject {
self.billingAddress.append(billingAddress)
}
if let paymentMethod = firstOrderDetails ["PayMentMethod"] as? AnyObject{
self.paymentMethod.append(paymentMethod)
}
guard let itemDetails = firstOrderDetails["Items detail"] as? [[String : AnyObject]] else {return}
self.itemsArray = itemDetails
}
}
}
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
I haven't compiled and run the code, so make sure you check for any typos/inconsistencies. Also, make sure you change the types of the objects you store are AnyObjects to specific types.
Here,
i have source latitude & longitude
in the same way i also have destination latitude & longitude
Now, i want to show the path between these two lat & long's
sourcelatitude = 12.9077869892472
sourcelongitude = 77.5870421156287
print(sourcelatitude!)
print(sourcelongitude!)
destinationlatitude = 12.907809
destinationlongitude = 77.587066
print(destinationlatitude!)
print(destinationlongitude!)
Could any one help me with this
Try this
let origin = "\(12.9077869892472),\(77.5870421156287)"
let destination = "\(12.907809),\(77.587066)"
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)")
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
if json["status"] as! String == "OK"
{
let routes = json["routes"] as! [[String:AnyObject]]
OperationQueue.main.addOperation({
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"] as! [String:String]
let points = routeOverviewPolyline["points"]
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .blue
polyline.strokeWidth = 4.0
polyline.map = mapViewX//Your GMSMapview
}
})
}
}catch let error as NSError{
print(error)
}
}
}).resume()
var aPosition = "30.9621,40.7816"
let bPosition = "26.9621,75.7816"
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(aPosition)&destination=\(bPosition)&key=\(your google key)"
//let urlString = "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=\(aPosition)&destinations=\(bPosition)&key=AIzaSyCaSIYkkv41RTn5vFLiSoZFlCUhIg-Db5c"
print(urlString)
Alamofire.request(urlString)
.responseJSON { response in
if let array = json["routes"] as? NSArray {
if let routes = array[0] as? NSDictionary{
if let overview_polyline = routes["overview_polyline"] as? NSDictionary{
if let points = overview_polyline["points"] as? String{
print(points)
// Use DispatchQueue.main for main thread for handling UI
DispatchQueue.main.async {
// show polyline
let path = GMSPath(fromEncodedPath:points)
self.polyline.path = path
self.polyline.strokeWidth = 4
self.polyline.strokeColor = UIColor.blue
self.polyline.map = self.mapView
}
}
}
}
}
I seem to have picked up a few errors since updating to swift 3
// Issue #1
let correctedAddress:String! = self.searchResults![(indexPath as NSIndexPath).row].addingPercentEncoding(withAllowedCharacters: CharacterSet.symbols)
print(correctedAddress)
let url = URL(string: "https://maps.googleapis.com/maps/api/geocode/json?address=\(correctedAddress)&sensor=false")
let task = URLSession.shared.dataTask(with: url!) {
data, response, error in
do {
if data != nil{
let dic = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
// Issue #2
let results = dic["results"] as! [String: Any]
let geometry = results["geometry"] as! [String: Any]
let location = geometry["location"] as! [String: Any]
let lat = location["lat"] as! Double
let lon = location["lng"] as! Double
self.delegate.locateWithLongitude(lon, andLatitude: lat)
}
}
catch {
print("Error")
}
}
task.resume()
issue #1:
correctedAddress, as an example, returns value "%51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61". Nevertheless, for some reason the url constant returns nil and causes a crash.
I don't understand why it returns nil. I can replace correctedAddress inside the url with the value %51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61 so the full url is
let url = NSURL(string: "https://maps.googleapis.com/maps/api/geocode/json?address=%51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61&sensor=false") and it works fine.
issue #2:
It crashes just at let results to which i get back the error of Could not cast value of type '__NSArrayI' (0x108bb0c08) to 'NSDictionary' (0x108bb1108).
Try the below code for your Issue#2
let results = dic["results"] as! NSArray
for result in results {
let strObj = result as! NSDictionary
let geometry = strObj["geometry"] as! NSDictionary
let location = geometry["location"] as! NSDictionary
let lat = location["lat"] as! NSNumber
let lon = location["lng"] as! NSNumber
}
For issue#1, try the below code
let valueAtIndex = self.searchResults![(indexPath as NSIndexPath).row].addingPercentEncoding(withAllowedCharacters: CharacterSet.symbols)
guard let correctedAddress = valueAtIndex else { return }
let adrString:String = "https://maps.googleapis.com/maps/api/geocode/json?address=\(correctedAddress)&sensor=false"
let url:URL = URL(string: adrString)!