I am currently working on developing an application that pulls data (Address and location information) from a php web service and displays the data as a string in a tableview cell. My tableview is embedded in a Navigation controller, when a cell is clicked a segue links to a map with several hard-coded pins on the map.
I am interested in creating a segue that links a tableview cell (Address) to a specific pin/annotation in a map as a direct reference to the address.
Additionally, I am interested in creating a custom annotation that displays data (Name, Address, photo etc.) regarding its location.
Ideally I am trying to recreate a simpler version of SpotHero.
Thanks!
Heres Some of my code:
TableController:
class TableController: UITableViewController {
var TableData:Array< String > = Array < String >()
var garagedata :Array<String> = Array < String >()
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://cgi.soic.indiana.edu/~team20/service.php")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BasicCell", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
//Wrap text in tableview
cell.textLabel?.numberOfLines=0
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//Automatic sizing of tableviewcells
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Segue to the second view controller
self.performSegue(withIdentifier: "detailSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// get a reference to the second view controller
let mapController = segue.destination as! MapController
// set a variable in the second view controller with the data to pass
mapController.receivedData = "Hello"
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let garages_list = json as? NSArray
{
let locations: NSMutableArray = NSMutableArray()
for i in 0 ..< data_list.count
/*{
print(TableData)
if let garage_obj = garages_list[i] as? NSDictionary
{
if let garage_name = garage_obj["GName"] as? String
{
if let garage_address = garage_obj["Address"] as? String
{
if let garage_code = garage_obj["Count"] as? String
{
if let garage_cap = garage_obj["Capacity"] as? String
{
TableData.append(garage_name + "\n"
+ garage_address + " [" + garage_code + "/" + garage_cap+"]")
garagedata.append(garage_name + "\n"
+ garage_address + " [" + garage_code + "/" + garage_cap+"]")
}
}
}
}
}}*/
{
let location = GarageModel()
if let garage_obj = garages_list[i] as? NSDictionary
{
//the following insures none of the JsonElement values are nil through optional binding
if let name = garage_obj["GName"] as? String,
let address = garage_obj["Address"] as? String,
let latitude = garage_obj["Latitude"] as? String,
let longitude = garage_obj["Longitude"] as? String,
let count = garage_obj["Count"] as? String
{
location.name = name
location.address = address
location.latitude = latitude
location.longitude = longitude
location.count = count
}
locations.add(location)
print(locations)
}
}}
DispatchQueue.main.async(execute: {self.do_table_refresh()})
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
GarageModel:
class GarageModel: NSObject {
//properties
var name: String?
var address: String?
var latitude: String?
var longitude: String?
var count: String?
var capacity: String?
//empty constructor
override init()
{
}
//construct with #name, #address, #latitude, and #longitude parameters
init(name: String, address: String, latitude: String, longitude: String, count: String, capacity: String) {
self.name = name
self.address = address
self.latitude = latitude
self.longitude = longitude
self.count = count
self.capacity = capacity
}
//prints object's current state
override var description: String {
return "Name: \(name), Address: \(address), Latitude: \(latitude), Longitude: \(longitude), Count: \(count), Capacity: \(capacity)"
}
}
I have hardcoded some pins for aesthetic/testing purposes but I do not have these dynamically appearing.
Map Controller:
class MapController : UIViewController {
#IBOutlet weak var mapView: MKMapView!
var receivedData = ""
override func viewDidLoad() {
super.viewDidLoad()
print(receivedData)
let latitude: CLLocationDegrees = 39.173294
let longitude: CLLocationDegrees = -86.520244
let latitude2: CLLocationDegrees = 39.163589
let longitude2: CLLocationDegrees = -86.526266
let latitude3: CLLocationDegrees = 39.167250
let longitude3: CLLocationDegrees = -86.515059
let latDelta: CLLocationDegrees = 0.05
let lonDelta: CLLocationDegrees = 0.05
let span = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let location2 = CLLocationCoordinate2D(latitude: latitude2, longitude: longitude2)
let location3 = CLLocationCoordinate2D(latitude: latitude3, longitude: longitude3)
let region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)
let garage1 = MKPointAnnotation()
garage1.title = "Fee Lane Parking Garage"
garage1.subtitle = "Count XX/150 \n 11th and Fee"
garage1.coordinate = location
mapView.addAnnotation(garage1)
let garage2 = MKPointAnnotation()
garage2.title = "Henderson Parking Garage"
garage2.subtitle = "Count XX/150 Fess and Atwater"
garage2.coordinate = location2
mapView.addAnnotation(garage2)
let garage3 = MKPointAnnotation()
garage3.title = "Jordan Parking Garage"
garage3.subtitle = "Count XX/150 North Jordan Street"
garage3.coordinate = location3
mapView.addAnnotation(garage3)
}
}
Related
below is my code. I want the value for Latitude and Longitude in my Poststring. But When he do the poststring my values are still nil because swift didn't update the location yet. So how can I wait for latitude and longitude before poststring gets the Values? I heard something of didset but I don't know how to use it and where I have to use it.
import Foundation
import CoreLocation
protocol FeedmodelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class Feedmodel: NSObject, URLSessionDataDelegate, CLLocationManagerDelegate {
weak var delegate: FeedmodelProtocol!
let locationManager = CLLocationManager() // create Location Manager object
var latitude : Double?
var longitude : Double?
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location: CLLocationCoordinate2D = manager.location?.coordinate else { return }
// set the value of lat and long
latitude = location.latitude
longitude = location.longitude
}
func downloadItems() {
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
// You will need to update your .plist file to request the authorization
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
let myUrl = URL(string: "http://example.com/stock_service4.php");
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
var request = URLRequest(url:myUrl!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
var postString = ""
if let lat = latitude, let long = longitude {
locationManager.stopUpdatingLocation()
postString = "lati=\(Int(lat))&longi=\(Int(long))"
// do task here now that postString is not empty
}
request.httpBody = postString.data(using: .utf8)
let task = defaultSession.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
print("error=\(String(describing: error))")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
print("error=\(String(describing: error))")
self.parseJSON(data)
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray;
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let stocks = NSMutableArray()
for i in 0 ..< jsonResult.count
{
print(jsonResult)
jsonElement = jsonResult[i] as! NSDictionary
let stock = Stockmodel()
//the following insures none of the JsonElement values are nil through optional binding
if let Datum = jsonElement["Datum"] as? String,
let Tankstelle = jsonElement["Tankstelle"] as? String,
let Kraftstoff1 = jsonElement["Kraftstoff1"] as? String,
let Preis1 = jsonElement["Preis1"] as? String,
let Kraftstoff2 = jsonElement["Kraftstoff2"] as? String,
let Preis2 = jsonElement["Preis2"] as? String,
let Notiz = jsonElement["Notiz"] as? String,
let longitude = jsonElement["longitude"] as? String,
let latitude = jsonElement["latitude"] as? String
{
print (Datum)
print(Tankstelle)
print(Kraftstoff1)
print(Preis1)
print(Kraftstoff2)
print(Preis2)
print(Notiz)
print(longitude)
print(latitude)
stock.Datum = Datum
stock.Tankstelle = Tankstelle
stock.Kraftstoff1 = Kraftstoff1
stock.Preis1 = Preis1
stock.Kraftstoff2 = Kraftstoff2
stock.Preis2 = Preis2
stock.Notiz = Notiz
stock.longitude = longitude
stock.latitude = latitude
}
stocks.add(stock)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: stocks)
})
}
}
Thank You!
The function locationManager(_:didUpdateLocations:) is called every time when the location is update. So you should add downloadItems() in the location manager like this :
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location: CLLocationCoordinate2D = manager.location?.coordinate else { return }
// set the value of lat and long
latitude = location.latitude
longitude = location.longitude
downloadItems()
}
See the documentation about locationManager(_:didUpdateLocations:)
So I'm in the middle of designing a social media application that displays posts, comprised of a picture and a description, on a newsfeed. I am able to upload posts to our database, however, I am having problems pulling the image from the database. Specifically, I am getting an error around the code
let image = post["path"] as! UIImage
Saying:
"Thread 1: signal SIGABRT", while the compiler says "Could not cast
value of type '__NSCFString' to 'UIImage'."
Here's the entirety of my code:
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var activities = [AnyObject]()
var images = [UIImage]()
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//tableView.contentInset = UIEdgeInsetsMake(2, 0, 0, 0)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return activities.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "activity", for: indexPath) as! CustomCell
let post = activities[indexPath.row]
print(post["path"])
let image = post["path"] as! UIImage
let username = post["username"] as? String
let text = post["text"] as? String
cell.titleLbl.text = text
cell.userLbl.text = username
cell.activityImage.image = image //as! UIImage
//cell.dateLbl.text = activities[indexPath.row]
//cell.activityImage.image = images[indexPath.row]
DispatchQueue.main.async {
}
return cell
}
override func viewWillAppear(_ animated: Bool) {
loadActivities()
}
func loadActivities() {
let id = user!["id"] as! String
let url = URL(string: "https://cgi.soic.indiana.edu/~team7/posts.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = "id=\(id)&text=&uuid="
request.httpBody = body.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// clean up
self.activities.removeAll(keepingCapacity: false)
self.images.removeAll(keepingCapacity: false)
//self.tableView.reloadData()
guard let parseJSON = json else {
print("Error while parsing")
return
}
guard let posts = parseJSON["posts"] as? [AnyObject] else {
print("Error while parseJSONing")
return
}
self.activities = posts
for i in self.activities.indices {
print("printed")
let path = self.activities[i]["path"] as? String
if let actualPath = path, !actualPath.isEmpty, let url = URL(string: actualPath) {
if let imageData = try? Data(contentsOf: url) {
if let image = UIImage(data: imageData) {
self.images.append(image)
print(self.images)
}
}
}
/*
if path != "" {
//let url = URL(string: path!)!
let url = URL(fileURLWithPath: path!)
let imageData = try? Data(contentsOf: url)
//let imageData = try? Data(contentsOf: url)
let image = UIImage(data: imageData!)!
self.images.append(image)
*/
else {
let image = UIImage()
self.images.append(image)
}
}
self.tableView.reloadData()
} catch {
}
} else {
}
})
}.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension NSMutableData {
func appendString(_ string : String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}
If there is anything you think I should do to improve or make the code run correctly, please let me know!
I've encountered a problem when I was working on my private project. I just improved my environment by buying a Virtual Private Server (VPS). I installed Apache, MySQL and PHP to be able to save data in a database followed by parsing it to a PHP and the final stage displaying it on an iOS app I'm creating.
I looked through quite few tutorials on the internet on how to retrieve the data from a php file and show it in a tableView and this is where my first problem is encountered. I'm not going to use a tableView and I for some reason have been struggling with just getting the data into an dictionary/array without any issues.
Problem:
I've followed a tutorial and made it work for a tableView but when I was trying to customize the output I don't manage to get it right.
I get the information to get saved to a dictionary but when I try to use the dictionary in any kind of way i get a breakpoint and the simulation just stops.
Code:
Class - LocationModel.swift
import Foundation
class LocationModel: NSObject {
var id: String?
var name: String?
var address: String?
var city: String?
var country: String?
var typ: String?
var lastresult: String?
override init() {
}
init(id: String, name: String, address: String, city: String, country: String, typ: String, lastresult: String) {
self.id = id
self.name = name
self.address = address
self.city = city
self.country = country
self.typ = typ
self.lastresult = lastresult
}
override var description: String {
return "Name: \(name), Address: \(address)"
}
}
Class - HomeModel.swift
import Foundation
protocol HomeModelProtocal: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
weak var delegate: HomeModelProtocal!
var data : NSMutableData = NSMutableData()
let urlPath: String = "http://server.truesight.se/risSwiftPHP/phptest.php"
func downloadItems() {
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){
if error != nil {
print("Failed to download data")
} else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
do {
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
let locations: NSMutableArray = NSMutableArray()
for item in jsonResult {
jsonElement = item as! NSDictionary
let location = LocationModel()
if let id = jsonElement["id"] as? String,
let name = jsonElement["name"] as? String,
let address = jsonElement["address"] as? String,
let city = jsonElement["city"] as? String,
let country = jsonElement["country"] as? String,
let typ = jsonElement["typ"] as? String,
let lastresult = jsonElement["lastresult"] as? String
{
print(id + name + address + country + city + typ + lastresult)
location.id = id
location.name = name
location.address = address
location.city = city
location.country = country
location.typ = typ
location.lastresult = lastresult
}
if let name = jsonElement["name"] as? String,
let address = jsonElement["address"] as? String
{
location.name = name
location.address = address
}
locations.addObject(location)
}
dispatch_async(dispatch_get_main_queue(), {() -> Void in
self.delegate.itemsDownloaded(locations)
})
}
}
It is un the method/function parseJSON in the class HomeModel where the breakpoint appears. It's the let location = LocationModel() that breaks the code. I've tried to search through the debug for more information and been using po $arg0 on the threads to try find more but I only get the error message Errored out in Execute, couldn't PrepareToExecuteJITExpression
I do get the jsonResult NSMutableArray filled with information and the jsonElement as well but after that it breaks.
I would really appreciate some help in the matter as I'm soon out of hair on my head because of this problem. If you find the solution bad or want any more information please just ask.
I feel like I've solved it but I'm not sure if it's the ultimate solution. I moved the following section from parserJSON to URLSession.
From parseJSON
var jsonResult: NSMutableArray = NSMutableArray()
do {
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
To function URLSession
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){
if error != nil {
print("Failed to download data")
} else {
print("Data downloaded")
var jsonResult: NSMutableArray = NSMutableArray()
do {
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
// Array is jsonResult,
// I sent it to my ViewController to control the output.
print(jsonResult)
var VC = ViewController()
VC.SomeMethod(jsonResult)
}
}
I been trying to implement a Pull to Refresh to my tableview to refresh JSON Data from server. On what I have tried on the debug Area screen it shows me the data reloads but the Cell labels and images doesn't refresh when I make changes on the PHP file on server .... I'M USING THE CODE BELOW:
import UIKit
class JSONData: UITableViewController {
var newsList = [News]()
override func viewDidLoad() {
super.viewDidLoad()
self.loadJSONDATA()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return newsList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! NewsStrings
let s = newsList[indexPath.row] as News
cell.labellName.text = s.newsName
cell.labelDesc.text = s.newsDesc
cell.labelDate.text = s.newsDate
cell.imgvImage.image = UIImage(named: "BgIcon.jpg")
if let img = UIImage(data: s.newsImage)
{
cell.imgvImage.image = img
}else
{
self.loadImages(s, indexPath: indexPath)
}
return cell
}
///////////////// JSON DATA ////////////////////////
func loadJSONDATA()
{
let urlString = "http://example.com/folder/JSON.php"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate:nil, delegateQueue: nil)
if let url = NSURL(string: urlString)
{
let request = NSURLRequest(URL: url)
let taskData = session.dataTaskWithRequest(request, completionHandler: {
(data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if (data != nil)
{
var parseError:NSError?
let parsedNews = (try! NSJSONSerialization.JSONObjectWithData(data!, options: [])) as! NSDictionary
//print("JSON Data \n \(parsedNews)")
if let news:AnyObject = parsedNews["News"]
{
self.parseJSON(news)
}
} else
{
}
})
taskData.resume()
}
}
/////////// LODING JSON DATA //////////////
func parseJSON(jsonData:AnyObject)
{
if let newsData = jsonData as? [[NSObject:AnyObject]]
{
var news:News
for s in newsData {
news = News()
if let sId:AnyObject = s["NewsID"]
{
if let NewsID = sId as? String
{
print("News id = \(NewsID)")
}
}
if let sn:AnyObject = s["newsName"]
{
if let newsName = sn as? String
{
news.newsName = newsName
//println("Store id = \(storeName)")
}
}
if let sn:AnyObject = s["newsDate"]
{
if let newsDate = sn as? String
{
news.newsDate = newsDate
//println("Store id = \(storeName)")
}
}
if let sn:AnyObject = s["newsIcon"]
{
if let newsIcon = sn as? String
{
news.newsImageName = newsIcon
//println("News Icon = \(newsIcon)")
}
}
if let sn:AnyObject = s["newsDesc"]
{
if let newsIcon = sn as? String
{
news.newsDesc = newsIcon
}
}
newsList += [news]
}
NSOperationQueue.mainQueue().addOperationWithBlock(){
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
self.tableView.reloadData()
}
}
}
/////////// LODING IMAGES FROM JSON DATA //////////////
func loadImages(news:News, indexPath:NSIndexPath)
{
let urlString = news.newsImageName
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate:nil, delegateQueue: nil)
if let url = NSURL(string: urlString)
{
let request = NSURLRequest(URL: url)
let taskData = session.dataTaskWithRequest(request, completionHandler: {
(data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if (data != nil)
{
news.newsImage = data!
let image = UIImage(data: data!)
dispatch_async(dispatch_get_main_queue(),{
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? NewsStrings {
cell.imgvImage.image = image
}
})
} else
{
}
})
taskData.resume()
}
}
}
You can add pull to refresh within your table view like below code,
var refreshControl = UIRefreshControl()
In view did load,
self.refreshControl.addTarget(self, action: Selector("loadJSONDATA"), forControlEvents: UIControlEvents.ValueChanged)
self.addSubview(self.refreshControl) // OR self.myTable?.addSubview(self.refreshControl)
Then add this line after self.parseJSON(news)
self.refreshControl.endRefreshing()
This will be help full to you. :)
I got something to make it work, this is what I have on my viewDidLoad:
self.refreshControl?.addTarget(self, action: #selector(NewsList.handleRefresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
The Function for the handleRefresh:
func handleRefresh(refreshControl: UIRefreshControl) {
newsList.removeAll() //<-This clear the whole tableview(labels, images,ect...)making table view blank
if self.refreshControl!.refreshing
{
self.loadRecords() //<-Reloads All data & labels
self.refreshControl!.endRefreshing()
}
}
The only thing is that the app crashes after doing the "Pull to refresh" multiples
I'm new to Swift and trying to set up an iOS app. At the start of the app I'm dropping a pin on the map and sending the location to my php web service. Then after the next 10 iterations through the map movement, another pin is to be dropped and the location gets sent to the service. Looking at the database everything is getting to the service and is getting loaded to the tables. But, the first time calling the service is the only time that the response data can be retrieved.
Here's the view controller:
//
// ViewController.swift
// Tracker
//
// Created by Kendall Crouch on 2/6/16.
// Copyright © 2016 KLC Computing. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
var places = [Dictionary<String, String>()]
var hasStarted: Bool = false
var locationCount = 0
var routeId: NSInteger = -1
var lastStep: NSInteger = -1
var markerId: Int = -1
var manager:CLLocationManager!
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var lblLatitude: UILabel!
#IBOutlet weak var lblLongitude: UILabel!
#IBOutlet weak var btnStartControl: UIBarButtonItem!
#IBOutlet weak var btnPauseControl: UIBarButtonItem!
#IBOutlet weak var btnStopControl: UIBarButtonItem!
#IBAction func btnStart(sender: AnyObject) {
btnStartControl.enabled = false
btnPauseControl.enabled = true
btnStopControl.enabled = true
manager.startUpdatingLocation()
}
#IBAction func btnPause(sender: AnyObject) {
manager.stopUpdatingLocation()
self.btnStartControl.enabled = true
self.btnPauseControl.enabled = false
hasStarted = false
}
#IBAction func btnStop(sender: AnyObject) {
manager.stopUpdatingLocation()
self.btnStopControl.enabled = false
self.btnStartControl.enabled = true
hasStarted = false
}
override func viewDidLoad() {
super.viewDidLoad()
locationCount = 500
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationCount += 1
let userLocation:CLLocation = locations[0]
let latitude: CLLocationDegrees = userLocation.coordinate.latitude
let longitude: CLLocationDegrees = userLocation.coordinate.longitude
lblLatitude.text = String(userLocation.coordinate.latitude)
lblLongitude.text = String(userLocation.coordinate.longitude)
let latDelta: CLLocationDegrees = 0.05
let lonDelta: CLLocationDegrees = 0.05
let span: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: false)
let newCoordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let newLocation = CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude)
if locationCount > 10 {
hasStarted = false
locationCount = 0
}
if !hasStarted {
hasStarted = true
CLGeocoder().reverseGeocodeLocation(newLocation) { (placemarks, error) -> Void in
var title = "Added on \(NSDate())"
if error != nil {
print(error)
}
else {
if let p = placemarks?[0] {
let formattedAddressLines = p.addressDictionary?["FormattedAddressLines"] as! NSArray
title = formattedAddressLines.componentsJoinedByString(", ")
}
}
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
annotation.title = title
self.mapView.addAnnotation(annotation)
self.places.append(["name":title, "lat":"\(newCoordinate.latitude)", "lon":"\(newCoordinate.longitude)"])
NSUserDefaults.standardUserDefaults().setObject(self.places, forKey: "places")
let url: NSURL = NSURL(string: "http://tracker.klccomputing.com/updateRoute.php")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let bodyData = "routeId=\(self.routeId)&routeName=\(title)&routeDate=\(NSDate())&lastStep=\(self.lastStep)&latitude=\(newLocation.coordinate.latitude)&longitude=\(newLocation.coordinate.longitude)"
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
print(data)
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let jsonData = json {
print("KLCA\(jsonData)")
if let newRouteId: NSInteger = jsonData["routeId"] as? NSInteger {
self.routeId = newRouteId
if let newLastStep: NSInteger = jsonData["lastStep"] as? NSInteger {
self.lastStep = newLastStep
print("KLCB\(self.lastStep)")
}
}
}
}
catch {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("raw response: \(responseString)")
}
}
}
})
task.resume()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Console information. I let the app run 3 iterations. The first time through the variable if statement to get the information from the variable jsonData worked. The second and third times through, they didn't work:
Optional(<7b22726f 75746549 64223a31 362c226d 61726b65 72496422 3a36312c 226c6173 74537465 70223a31 7d>)
KLCA{
lastStep = 1;
markerId = 61;
routeId = 16;
}
KLCB1
Optional(<7b22726f 75746549 64223a22 3136222c 226d6172 6b657249 64223a36 322c226c 61737453 74657022 3a327d>)
KLCA{
lastStep = 2;
markerId = 62;
routeId = 16;
}
Optional(<7b22726f 75746549 64223a22 3136222c 226d6172 6b657249 64223a36 332c226c 61737453 74657022 3a327d>)
KLCA{
lastStep = 2;
markerId = 63;
routeId = 16;
}