Annotations are not showing in MKMapView? - ios

I am doing a projects by following this tutorial enter link description here in swift3 Xcode 8.2.1.
I want to get 10 Nearest Restaurants from my current location.
But Still I can't get any data as map pins or tableview.
Please help me I am new to Swift.
Please find whole coding here including pod file.
Pod File
'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target "FSResturant" do
pod 'QuadratTouch',
:git => 'https://github.com/Constantine-Fry/das-quadrat', :branch => 'fry-swift30'
pod 'RealmSwift'
end
ResturantAPI.swift
import Foundation
import QuadratTouch
import MapKit
import Realm
import RealmSwift
//Create Venues Struct
struct API
{
struct notifications
{
static let venuesUpdated = "venues_updated"
}
}
class ResturantAPI
{
static let sharedInstance = ResturantAPI()
var session:Session?
init()
{
// Initialize the Foursquare client API Keys
let client = Client(clientID: "XXXX", clientSecret: "XXXX", redirectURL: "")
let configuration = Configuration(client:client)
Session.setupSharedSessionWithConfiguration(configuration)
self.session = Session.sharedSession()
}
//getting venue data from FOURSQUARE
func getResturantsWithLocation(location:CLLocation)
{
//function body
if let session = self.session
{
//this category Id will receive nearby halal resturants in dubai
var parameters = location.parameters()
parameters += [Parameter.categoryId: "52e81612bcbc57f1066b79ff"]
parameters += [Parameter.radius: "2000"]
parameters += [Parameter.limit: "10"]
// Start a "search", i.e. an async call to Foursquare that should return venue data
let searchTask = session.venues.search(parameters)
{
(result) -> Void in
if let response = result.response
{
if let venues = response["venues"] as? [[String: AnyObject]]
{
autoreleasepool
{
let realm = try! Realm()
realm.beginWrite()
for venue:[String: AnyObject] in venues
{
let venueObject:Venue = Venue()
if let id = venue["id"] as? String
{
venueObject.id = id
}
if let name = venue["name"] as? String
{
venueObject.name = name
}
if let location = venue["location"] as? [String: AnyObject]
{
if let longitude = location["lng"] as? Float
{
venueObject.longitude = longitude
}
if let latitude = location["lat"] as? Float
{
venueObject.latitude = latitude
}
if let formattedAddress = location["formattedAddress"] as? [String]
{
venueObject.address = formattedAddress.joined(separator: " ")
}
}
realm.add(venueObject, update: true)
}
do {
try realm.commitWrite()
print("Committing write...")
}
catch (let e)
{
print("Y U NO REALM ? \(e)")
}
}
NotificationCenter.default.post(name: Foundation.Notification.Name(rawValue: API.notifications.venuesUpdated), object:nil, userInfo:nil)
}
}
}
searchTask.start()
}
}
}
extension CLLocation
{
func parameters() -> Parameters
{
let ll = "\(self.coordinate.latitude),\(self.coordinate.longitude)"
// let near = "Dubai"
let llAcc = "\(self.horizontalAccuracy)"
// let llAcc = "10000.0"
let alt = "\(self.altitude)"
// let alt = "0"
let altAcc = "\(self.verticalAccuracy)"
// let altAcc = "10000.0"
// let query = "resturants"
let parameters = [
Parameter.ll:ll,
// Parameter.near:near,
Parameter.llAcc:llAcc,
Parameter.alt:alt,
Parameter.altAcc:altAcc,
// Parameter.query:query
]
return parameters
}
}
ViewController.swift
import UIKit
import MapKit
import RealmSwift
import Realm
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UITableViewDataSource, UITableViewDelegate {
//Initialize the Map View
#IBOutlet var mapView:MKMapView?
//To get the user location
var locationManager:CLLocationManager?
//Span view in meters default
let distanceSpan:Double = 500
//show user's location on the map
var lastLocation:CLLocation?
// Stores venues from Realm, as a non-lazy list
var venues:[Venue]?
//Initializing the table view
#IBOutlet var tableView1:UITableView?
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.onVenuesUpdated(_:)), name: NSNotification.Name(rawValue: API.notifications.venuesUpdated), object: nil);
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
//Initializing mapview delegate to display
if let mapView = self.mapView
{
mapView.delegate = self
}
//Initializing UITableview delegate to display
if let tableView1 = self.tableView1
{
tableView1.delegate = self
tableView1.dataSource = self
}
}
override func viewDidAppear(_ animated: Bool)
{
if locationManager == nil
{
locationManager = CLLocationManager()
locationManager!.delegate = self
locationManager!.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager!.requestAlwaysAuthorization()
// Don't send location updates with a distance smaller than 50 meters between them
locationManager!.distanceFilter = 50
locationManager!.startUpdatingLocation()
}
}
// UITable View Delegates
func tableView(_ tableView1: UITableView, numberOfRowsInSection section: Int) -> Int
{
return venues?.count ?? 0
}
func numberOfSections(in tableView1: UITableView) -> Int {
return 1
}
func tableView(_ tableView1: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView1.dequeueReusableCell(withIdentifier: "cellIdentifier");
if cell == nil
{
cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cellIdentifier")
}
if let venue = venues?[indexPath.row]
{
cell!.textLabel?.text = venue.name
cell!.detailTextLabel?.text = venue.address
}
return cell!
}
func tableView(_ tableView1: UITableView, didSelectRowAt indexPath: IndexPath) {
if let venue = venues?[indexPath.row]
{
let region = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2D(latitude: Double(venue.latitude), longitude: Double(venue.longitude)), distanceSpan, distanceSpan)
mapView?.setRegion(region, animated: true)
}
}
func refreshVenues(_ location: CLLocation?, getDataFromFoursquare:Bool = false)
{
if location != nil
{
lastLocation = location
}
if let location = lastLocation
{
if getDataFromFoursquare == true
{
ResturantAPI.sharedInstance.getResturantsWithLocation(location: location)
}
// Convenience method to calculate the top-left and bottom-right GPS coordinates based on region (defined with distanceSpan)
let (start, stop) = calculateCoordinatesWithRegion(location);
// Set up a predicate that ensures the fetched venues are within the region
let predicate = NSPredicate(format: "latitude < %f AND latitude > %f AND longitude > %f AND longitude < %f", start.latitude, stop.latitude, start.longitude, stop.longitude);
let realm = try! Realm()
venues = realm.objects(Venue.self).filter(predicate).sorted {
location.distance(from: $0.coordinate) < location.distance(from: $1.coordinate);
};
for venue in venues!
{
let annotation = ResturantAnnotation(title: venue.name, subtitle: venue.address, coordinate: CLLocationCoordinate2D(latitude: Double(venue.latitude), longitude: Double(venue.longitude)));
mapView?.addAnnotation(annotation);
}
// RELOAD ALL THE DATAS !!!
tableView1?.reloadData()
}
}
//Delegate Method of CLLocation Manager
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation)
{
if let mapView = self.mapView
{
let region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, distanceSpan, distanceSpan)
mapView.setRegion(region, animated: true)
refreshVenues(newLocation, getDataFromFoursquare: true)
}
}
//Adds Annotations in the Map View
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation.isKind(of: MKUserLocation.self)
{
return nil
}
var view = mapView.dequeueReusableAnnotationView(withIdentifier: "annotationIdentifier");
if view == nil
{
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "annotationIdentifier")
}
view?.canShowCallout = true
return view
}
func onVenuesUpdated(_ notification:Foundation.Notification)
{
// When new data from Foursquare comes in, reload from local Realm
refreshVenues(nil);
}
func calculateCoordinatesWithRegion(_ location:CLLocation) -> (CLLocationCoordinate2D, CLLocationCoordinate2D)
{
let region = MKCoordinateRegionMakeWithDistance(location.coordinate, distanceSpan, distanceSpan);
var start:CLLocationCoordinate2D = CLLocationCoordinate2D();
var stop:CLLocationCoordinate2D = CLLocationCoordinate2D();
start.latitude = region.center.latitude + (region.span.latitudeDelta / 2.0);
start.longitude = region.center.longitude - (region.span.longitudeDelta / 2.0);
stop.latitude = region.center.latitude - (region.span.latitudeDelta / 2.0);
stop.longitude = region.center.longitude + (region.span.longitudeDelta / 2.0);
return (start, stop);
}
Venue.swift
import Foundation
import RealmSwift
import MapKit
class Venue: Object
{
dynamic var id:String = ""
dynamic var name:String = ""
dynamic var latitude:Float = 0
dynamic var longitude:Float = 0
dynamic var address:String = ""
var coordinate:CLLocation {
return CLLocation(latitude: Double(latitude), longitude: Double(longitude));
}
//The the primary key to Realm
override static func primaryKey() -> String?
{
return "id";
}
}
ResturantAnnotation.swift
import Foundation
import MapKit
class ResturantAnnotation: NSObject, MKAnnotation
{
let title:String?
let subtitle:String?
let coordinate: CLLocationCoordinate2D
init(title:String?, subtitle:String?, coordinate:CLLocationCoordinate2D)
{
self.title=title
self.subtitle=subtitle
self.coordinate=coordinate
super.init();
}
}
Can Anybody figure out what is the mistake here, that not showing responses in the map and tableview.
Thanks.

Related

Delete contents of JSON object via table view controller - SWIFT

I am working on an iOS application which tracks user locations and 1) displays them as map annotation objects and 2) displays the data in a table view controller. The data contained in the table view controller is stored on the end user's iOS device as a JSON file. I am having an issue where I cannot get the records within the JSON file to delete even though delete has been enabled in the code for the table view controller.
I need another pair of eyes to look at the code and hopefully tell me what I'm missing.
The code consists of the following files:
MapViewController.swift
PlacesTableViewController.swift
Location.swift
LocationsStorage.swift
Extension to AppDelegate.swift (Only pertinent code included here)
The contents of the files are as follows:
MapViewController.swift *
import UIKit
import MapKit
class MapViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.userTrackingMode = .follow
let annotations = LocationsStorage.shared.locations.map { annotationForLocation($0) }
mapView.addAnnotations(annotations)
NotificationCenter.default.addObserver(self, selector: #selector(newLocationAdded(_:)), name: .newLocationSaved, object: nil)
}
#IBAction func addItemPressed(_ sender: Any) {
guard let currentLocation = mapView.userLocation.location else {
return
}
LocationsStorage.shared.saveCLLocationToDisk(currentLocation)
}
// Delete location pin from mapview
#IBAction func removeItemPressed(_ sender: Any) {
guard let currentLocation = mapView.userLocation.location else {
return
}
LocationsStorage.shared.saveCLLocationToDisk(currentLocation)
}
func annotationForLocation(_ location: Location) -> MKAnnotation {
let annotation = MKPointAnnotation()
annotation.title = location.dateString
annotation.coordinate = location.coordinates
return annotation
}
#objc func newLocationAdded(_ notification: Notification) {
guard let location = notification.userInfo?["location"] as? Location else {
return
}
let annotation = annotationForLocation(location)
mapView.addAnnotation(annotation)}}
PlacesTableViewController.swift *
import UIKit
import UserNotifications
class PlacesTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(newLocationAdded(_:)),
name: .newLocationSaved,
object: nil)
}
#objc func newLocationAdded(_ notification: Notification) {
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return LocationsStorage.shared.locations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceCell", for: indexPath)
let location = LocationsStorage.shared.locations[indexPath.row]
cell.textLabel?.numberOfLines = 3
cell.textLabel?.text = location.description
cell.detailTextLabel?.text = location.dateString
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 110
}
// Enables swipe-to-delete functionality in table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
LocationsStorage.shared.locations.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
tableView.reloadData()
}
}
}
Location.swift *
import Foundation
import CoreLocation
class Location: Codable {
static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
return formatter
}()
var coordinates: CLLocationCoordinate2D {
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
let latitude: Double
let longitude: Double
let date: Date
let dateString: String
let description: String
init(_ location: CLLocationCoordinate2D, date: Date, descriptionString: String) {
latitude = location.latitude
longitude = location.longitude
self.date = date
dateString = Location.dateFormatter.string(from: date)
description = descriptionString
}
convenience init(visit: CLVisit, descriptionString: String) {
self.init(visit.coordinate, date: visit.arrivalDate, descriptionString: descriptionString)
}
}
LocationsStorage.swift *
import Foundation
import CoreLocation
class LocationsStorage {
static let shared = LocationsStorage()
//private(set) var locations: [Location]
var locations: [Location]
let fileManager: FileManager
// documentsURL cannot be private expression.
let documentsURL: URL
init() {
let fileManager = FileManager.default
// Location JSON file is stored in user's home directory on iOS. Inaccessible to PC/Mac hardware but can be accessed by application.
documentsURL = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
self.fileManager = fileManager
let jsonDecoder = JSONDecoder()
let locationFilesURLs = try! fileManager.contentsOfDirectory(at: documentsURL,
includingPropertiesForKeys: nil)
locations = locationFilesURLs.compactMap { url -> Location? in
guard !url.absoluteString.contains(".DS_Store") else {
return nil
}
guard let data = try? Data(contentsOf: url) else {
return nil
}
return try? jsonDecoder.decode(Location.self, from: data)
}.sorted(by: { $0.date < $1.date })
}
// Saves location data to JSON object within user directory
func saveLocationOnDisk(_ location: Location) {
let encoder = JSONEncoder()
let timestamp = location.date.timeIntervalSince1970
let fileURL = documentsURL.appendingPathComponent("\(timestamp)")
let data = try! encoder.encode(location)
try! data.write(to: fileURL)
locations.append(location)
NotificationCenter.default.post(name: .newLocationSaved, object: self, userInfo: ["location": location])
}
func saveCLLocationToDisk(_ clLocation: CLLocation) {
let currentDate = Date()
AppDelegate.geoCoder.reverseGeocodeLocation(clLocation) { placemarks, _ in
if let place = placemarks?.first {
let location = Location(clLocation.coordinate, date: currentDate, descriptionString: "\(place)")
self.saveLocationOnDisk(location)
}
}
}
}
extension Notification.Name {
static let newLocationSaved = Notification.Name("newLocationSaved")
}
Extension to AppDelegate.swift *
// Journaling-specific variables
static let geoCoder = CLGeocoder()
let center = UNUserNotificationCenter.current()
let locationManager = CLLocationManager()
... [other code here, not related to question]
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
// create CLLocation from the coordinates of CLVisit
let clLocation = CLLocation(latitude: visit.coordinate.latitude, longitude: visit.coordinate.longitude)
// Get location description
AppDelegate.geoCoder.reverseGeocodeLocation(clLocation) { placemarks, _ in
if let place = placemarks?.first {
let description = "\(place)"
self.newVisitReceived(visit, description: description)
}
}
}
func newVisitReceived(_ visit: CLVisit, description: String) {
let location = Location(visit: visit, descriptionString: description)
LocationsStorage.shared.saveLocationOnDisk(location)
let content = UNMutableNotificationContent()
content.title = "New Location Logged 📌"
content.body = location.description
content.sound = UNNotificationSound.default
// UNTimeIntervalNotificationTrigger is set to 10 minutes. User must spend 10 minutes at a location before a notificatin will be triggered and a log will be created.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: (10*60), repeats: false)
let request = UNNotificationRequest(identifier: location.dateString, content: content, trigger: trigger)
center.add(request, withCompletionHandler: nil)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
return
}
AppDelegate.geoCoder.reverseGeocodeLocation(location) { placemarks, _ in
if let place = placemarks?.first {
let description = "Fake visit: \(place)"
let fakeVisit = FakeVisit(coordinates: location.coordinate, arrivalDate: Date(), departureDate: Date())
self.newVisitReceived(fakeVisit, description: description)
}
}
}
}
final class FakeVisit: CLVisit {
private let myCoordinates: CLLocationCoordinate2D
private let myArrivalDate: Date
private let myDepartureDate: Date
override var coordinate: CLLocationCoordinate2D {
return myCoordinates
}
override var arrivalDate: Date {
return myArrivalDate
}
override var departureDate: Date {
return myDepartureDate
}
init(coordinates: CLLocationCoordinate2D, arrivalDate: Date, departureDate: Date) {
myCoordinates = coordinates
myArrivalDate = arrivalDate
myDepartureDate = departureDate
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Interestingly, when I am able to delete the records within the table view controller, they appear to delete until the next time the app launches, at which time they are back and still visible.
Any help would be appreciated.
As paulw11 stated in comments, needed to save JSON to disk after performing delete action.

Displaying multiple driver annotations around the user (with Database)

Im new in coding. is there a way to show multiple drivers around the user.
.
I've already figured out how to show a list of drivers near the user thru database, now I want the map to show the drivers near the user.
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import MapKit
class EmployeeTableViewController: UITableViewController, CLLocationManagerDelegate {
#IBOutlet weak var jobsAvailableMap: MKMapView!
var jobRequests : [DataSnapshot] = []
var locationManager = CLLocationManager()
var employeeLocation = CLLocationCoordinate2D()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
Database.database().reference().child("JobRequests").observe(.childAdded) { (snapshot) in
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let employeeLat = jobRequestDictionary["employeeLat"] as? Double {
} else {
self.jobRequests.append(snapshot)
self.tableView.reloadData()
}
}
}
Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { (timer) in
self.tableView.reloadData()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let coord = manager.location?.coordinate {
employeeLocation = coord
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return jobRequests.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "jobRequestCell", for: indexPath)
let snapshot = jobRequests[indexPath.row]
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let email = jobRequestDictionary["email"] as? String {
if let lat = jobRequestDictionary["lat"] as? Double {
if let lon = jobRequestDictionary["lon"] as? Double {
let employeeCLLocation = CLLocation(latitude: employeeLocation.latitude, longitude: employeeLocation.longitude)
let employerCLLocation = CLLocation(latitude: lat, longitude: lon)
let distance = employeeCLLocation.distance(from: employerCLLocation) / 1000
let roundedDistance = round(distance * 100) / 100
cell.textLabel?.text = "\(email) - \(roundedDistance)km away"
}
}
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let snapshot = jobRequests[indexPath.row]
performSegue(withIdentifier: "acceptSegue", sender: snapshot)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let acceptVC = segue.destination as? AcceptJobViewController {
if let snapshot = sender as? DataSnapshot {
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let email = jobRequestDictionary["email"] as? String {
if let lat = jobRequestDictionary["lat"] as? Double {
if let lon = jobRequestDictionary["lon"] as? Double {
acceptVC.requestEmail = email
let location = CLLocationCoordinate2D(latitude: lat, longitude: lon)
acceptVC.requestLocation = location
acceptVC.employeeLocation = employeeLocation
}
}
}
}
}
}
}
#IBAction func logoutTapped(_ sender: Any) {
try? Auth.auth().signOut()
navigationController?.dismiss(animated: true, completion: nil)
}
}
I'm trying to look for tutorials online but most are not connected to Firebase Database.
You can use addAnnotation method.
e.g. (no guarantee you can build the following code)
func addDriverAnnotation(snapshot: DataSnapshot){
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let email = jobRequestDictionary["email"] as? String {
if let lat = jobRequestDictionary["lat"] as? Double {
if let lon = jobRequestDictionary["lon"] as? Double {
let annotation = MKAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(lat, lon)
annotation.title = "title"
annotation.subtitle = "subtitle"
self.jobsAvailableMap.addAnnotation(annotation)
}
}
}
}
}
You need to call this method in Database.database()... method.
Database.database().reference().child("JobRequests").observe(.childAdded) { (snapshot) in
if let jobRequestDictionary = snapshot.value as? [String:AnyObject] {
if let employeeLat = jobRequestDictionary["employeeLat"] as? Double {
} else {
self.jobRequests.append(snapshot)
self.tableView.reloadData()
self.addDriverAnnotation(snapshot: snapshot)
}
}
}

How to use data from a structure array

I want to use the latitude and logitude values ​​in the structure array to represent polylines.
You can use the list[1].latitude value from json in the view, but if you try to use the list[1].latitude value from the override func viewDidLoad () above, you get an error.
How can I use this value as a polyline's latitude and longitude value?
Swift Source
import UIKit
import GoogleMaps
class TableController: UIViewController, GMSMapViewDelegate , UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var viewMap: GMSMapView!
#IBOutlet weak var listTableView: UITableView!
//JSON담을 구조
var list:[MyStruct] = [MyStruct]()
struct MyStruct
{
var index = ""
var ip = ""
var latitude = ""
var longitude = ""
var zonename = ""
init(_ index:String, _ ip:String, _ latitude:String, _ longitude:String, _ zonename:String)
{
self.index = index
self.ip = ip
self.latitude = latitude
self.longitude = longitude
self.zonename = zonename
}
}
override func viewDidLoad() {
super.viewDidLoad()
// set initial location
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: 37.209037, longitude: 126.976370, zoom: 16.0)
viewMap.camera = camera
let count: Int = 0
//폴리라인
let path = GMSMutablePath()
path.add(CLLocationCoordinate2DMake(37.209037, 126.976370))
path.add(CLLocationCoordinate2DMake(37.211643, 126.972444))
path.add(CLLocationCoordinate2DMake(37.211457, 126.972147))
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 6.0
polyline.map = viewMap
listTableView.dataSource = self
listTableView.delegate = self
get_data("http://192.168.0.11/fence.php")
}
func get_data(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = URLRequest(url: url)
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
self.extract_data(data)
})
task.resume()
}
func extract_data(_ data:Data?)
{
let json:Any?
if(data == nil)
{
return
}
do{
json = try JSONSerialization.jsonObject(with: data!, options: [])
}
catch
{
return
}
guard let data_array = json as? NSArray else
{
return
}
for i in 0 ..< data_array.count
{
if let data_object = data_array[i] as? NSDictionary
{
if let data_index = data_object["index"] as? String,
let data_ip = data_object["Ip"] as? String,
let data_latitude = data_object["Latitude"] as? String,
let data_longitude = data_object["Longitude"] as? String,
let data_Zonename = data_object["ZoneName"] as? String
{
list.append(MyStruct(data_index, data_ip, data_latitude, data_longitude, data_Zonename))
}
}
}
refresh_now()
}
func refresh_now()
{
DispatchQueue.main.async(
execute:
{
self.listTableView.reloadData()
})
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return list.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = list[indexPath.row].zonename + " : " + list[indexPath.row].latitude
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Cell data not showing up in UITableView?

Any idea how i can be making this GET request with Alamofire - getting exactly what I want back - passing the info to the func tableView(tableView: UITableView - populating and returning each cell and yet my table, simply, will not show the loaded data?
From within the AlamoFire promised return i call self.refresh() which calls this in the main thread:
func refresh() {
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
});
--
Any ideas? This is literally driving me nuts. Thanks for any ideas or solutions in advance!
import UIKit
import Alamofire
import MapKit
class ListViewController: UIViewController, UISearchBarDelegate, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {
var tools = [Tool]()
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
let locationManager = CLLocationManager()
var currentLat: CLLocationDegrees = 0.0
var currentLong: CLLocationDegrees = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
searchBar.delegate = self
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 116
self.tableView.registerClass(ToolTableViewCell.self, forCellReuseIdentifier: "ToolTableViewCell")
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
// if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
// print("locations = \(locValue.latitude) \(locValue.longitude)")
let location = locations.last! as CLLocation
currentLat = location.coordinate.latitude
currentLong = location.coordinate.longitude
}
func searchBarSearchButtonClicked(searchbar: UISearchBar)
{
searchbar.resignFirstResponder()
tools = []
let defaults = NSUserDefaults.standardUserDefaults()
let userid: Int = defaults.objectForKey("toolBeltUserID") as! Int
let searchTerm = String(searchBar.text!)
print(searchTerm)
Alamofire.request(.GET, "http://localhost:3000/tools/search", parameters: ["keyword": searchTerm, "latitude": currentLat, "longitude": currentLong,
"user": userid]) .responseJSON {response in
if let JSON = response.result.value {
print("\(JSON)")
for i in 0 ..< JSON.count {
let owner = JSON[i].objectForKey("owner")
let tool = JSON[i].objectForKey("tool")
let title = tool!["title"] as! String!
let ownerId = owner!["id"] as! Int!
let distanceToTool = JSON[i].objectForKey("distance") as! Double
var description: String
if let des = tool!["description"] as? NSNull {
description = ""
} else {
description = (tool!["description"] as? String!)!
}
let myTool = Tool(title: title!, description: description, ownerId: ownerId!, distance: distanceToTool)
self.tools.append(myTool)
}
// dispatch_async(dispatch_get_main_queue(), {
self.refresh()
// })
} else {
print("Sent search term, but no response")
}
}
}
func refresh() {
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
});
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(tools.count)
return tools.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ToolTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as!ToolTableViewCell
let tool = tools[indexPath.row]
if(indexPath.row==0){
cell.title?.text = tool.title
// print(tool.title)
// cell.toolListDescription?.text = tool.description
cell.ownerId = tool.ownerId
// print(tool.ownerId)
// print(tool.distance)
// cell.distance?.text = "\(tool.distance)mi"
}
print(cell)
return cell
}
}
make sure you set the Reuse Identifier in the attribute inspector! in my case it was 'ToolTableViewCell'
Thanks!

Swift-Xcode: why isn't my self.tableView.reloadData() call loading the promised data into my table / cells?

HERE is the latest code. I've tried moving the tableView.reloadData() all over the place - anyone have any ideas or suggestions? I am still staring at an empty table that says "no results" when i make my API call and get exactly what I need in return.
I have also reset the constraints all over my storyboard - I feel like I am missing something very simple here
import UIKit
import Alamofire
import MapKit
//import CoreLocation
class ToolTableViewController: UITableViewController, CLLocationManagerDelegate {
// #IBOutlet weak var tableview: UITableView!
var jsonArray:NSMutableArray?
var tools = [Tool]()
#IBOutlet weak var toolListSearchBar: UISearchBar!
let locationManager = CLLocationManager()
var currentLat: CLLocationDegrees = 0.0
var currentLong: CLLocationDegrees = 0.0
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
// print("locations = \(locValue.latitude) \(locValue.longitude)")
let location = locations.last! as CLLocation
currentLat = location.coordinate.latitude
currentLong = location.coordinate.longitude
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
dispatch_async(dispatch_get_main_queue(), { self.tableView.reloadData() })
self.tableView.registerClass(ToolTableViewCell.self, forCellReuseIdentifier: "ToolTableViewCell")
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
else{
print("Location service disabled");
}
// self.tableView.reloadData()
// Load the sample data.
}
func refresh(sender: AnyObject) {
// Reload the data
self.tableView.reloadData()
}
func searchBarSearchButtonClicked(searchbar: UISearchBar)
{
searchbar.resignFirstResponder()
tools = []
let defaults = NSUserDefaults.standardUserDefaults()
let userid: Int = defaults.objectForKey("toolBeltUserID") as! Int
let searchTerm = String(toolListSearchBar.text!)
print(searchTerm)
Alamofire.request(.GET, "http://localhost:3000/tools/search", parameters: ["keyword": searchTerm, "latitude": currentLat, "longitude": currentLong,
"user": userid]) .responseJSON {response in
if let JSON = response.result.value {
print("\(JSON)")
for i in 0 ..< JSON.count {
let owner = JSON[i].objectForKey("owner")
let tool = JSON[i].objectForKey("tool")
let title = tool!["title"] as! String!
let ownerId = owner!["id"] as! Int!
let distanceToTool = JSON[i].objectForKey("distance") as! Double
var description: String
if let des = tool!["description"] as? NSNull {
description = ""
} else {
description = (tool!["description"] as? String!)!
}
let myTool = Tool(title: title!, description: description, ownerId: ownerId!, distance: distanceToTool)
self.tools.append(myTool)
}
} else {
print("Sent search term, but no response")
}
self.refresh(self)
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tools.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ToolTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ToolTableViewCell
let tool = tools[indexPath.row]
cell.title?.text = tool.title
// print(tool.title)
// cell.toolListDescription?.text = tool.description
cell.ownerId = tool.ownerId
// print(tool.ownerId)
// print(tool.distance)
// cell.distance?.text = "\(tool.distance)mi"
print(cell)
return cell
print(cell)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The call to reloadData belongs inside the completion closure for the Alamofire request.
Where have it now it's getting called before the Alamofire request call is complete.
I don't remember if Alamofire's completion closures are run on the main thread or on a background thread. If they're run on a background thread then you'll need to wrap the call to reloadData in a dispatch_async(dispatch_get_main_queue){ } call.
EDIT:
I said the call to reloadData belongs inside the closure for the Alamofire request call. Like this:
Alamofire.request(.GET, "http://localhost:3000/tools/search", parameters: ["keyword": searchTerm, "latitude": currentLat, "longitude": currentLong,
"user": userid]) .responseJSON {response in
if let JSON = response.result.value {
print("\(JSON)")
for i in 0 ..< JSON.count {
let owner = JSON[i].objectForKey("owner")
let tool = JSON[i].objectForKey("tool")
let title = tool!["title"] as! String!
let ownerId = owner!["id"] as! Int!
let distanceToTool = JSON[i].objectForKey("distance") as! Double
var description: String
if let des = tool!["description"] as? NSNull {
description = ""
} else {
description = (tool!["description"] as? String!)!
}
let myTool = Tool(title: title!, description: description, ownerId: ownerId!, distance: distanceToTool)
self.tools.append(myTool)
}
//This call is inside the closure for the request call.
dispatch_async(dispatch_get_main_queue())
{
//Call reloadData from the main thread
self.tableView.reloadData()
//Or you could call your refresh method.
}
} else {
print("Sent search term, but no response")
}
}
}

Resources