Transferring Data Between Views, Saving in UserDefaults - swift

I am having a problem in my app where my label (goalLabel) won't get changed to the goal let (which is set in UserDefaults) on the app open. It will get changed to null for some reason. The code below should check if the data that gets trasnmitted from another view controller (Where the goal is set) is equal to null. if it isnt itll change it to whatever the goalDataPassed is but if it is equal to null (Which it should be on app open) it should change it to whatever is saved in userdefaults.
SecondViewController (Where the label should appear):
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
#IBOutlet weak var goalLabel: UILabel!
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
var firstDataPassed:String!
var secondDataPassed:String!
var goalDataPassed:String!
let defaults = UserDefaults.standard
let name = UserDefaults.standard.string(forKey: "name")
let job = UserDefaults.standard.string(forKey: "job")
let goal = UserDefaults.standard.string(forKey: "goal")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
nameLabel.text = name
jobLabel.text = job
goalLabel.text = goal
if (firstDataPassed != "") {
nameLabel.text = firstDataPassed
}
if (secondDataPassed != "") {
jobLabel.text = secondDataPassed
}
if (goalDataPassed != "") {
goalLabel.text = goalDataPassed
}
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
let initialLocation = CLLocation(latitude: -34.9285, longitude: 138.6007)
let regionRadius: CLLocationDistance = 20000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius, regionRadius)
mapView.setRegion(coordinateRegion, animated: true)
}
centerMapOnLocation(location: initialLocation)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation = locations.last
let viewRegion = MKCoordinateRegionMakeWithDistance((userLocation?.coordinate)!, 10000, 10000)
self.mapView.setRegion(viewRegion, animated: true)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

As an example: You can make firstDataPassed an optional and then do the assignment the following way:
nameLabel.text = firstDataPassed ?? name!
If firstDataPassed is nil, name! will be used for the text. And if name! crashes you know that the default value is bad.
You could also check for firstDataPassed to be the empty string, but if the other viewController sets firstDataPassed if it should be used then that is not necessary.

Related

Hide Button if TextFields are Empty Equation Not Working

I have 2 different textfields and I want to hide the button if these textfields are empty, and make this button visible when it is filled. I made an equation like below. The button does not appear on the first boot, but it does not appear when I fill in the data. Where is wrong?
var secilenLatitude = Double()
var secilenLongitude = Double()
#IBOutlet weak var isimTextField: UITextField!
#IBOutlet weak var notTextField: UITextField!
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var lokasyonuKaydet: UIButton!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(konumSec(gestureRecognizer:)))
mapView.addGestureRecognizer(gestureRecognizer)
let keyboardGR = UITapGestureRecognizer(target: self, action: #selector(klavyeyiKapat))
self.view.addGestureRecognizer(keyboardGR)
if isimTextField.text!.isEmpty == true && notTextField.text!.isEmpty == true {
lokasyonuKaydet.isHidden = true
} else {
lokasyonuKaydet.isHidden = false
}
}
#objc func klavyeyiKapat() {
view.endEditing(true)
}
#objc func konumSec(gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
let dokunulanNokta = gestureRecognizer.location(in: mapView)
let dokunulanKoordinat = mapView.convert(dokunulanNokta, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = dokunulanKoordinat
annotation.title = isimTextField.text
annotation.subtitle = notTextField.text
mapView.addAnnotation(annotation)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = CLLocationCoordinate2D.init(latitude: locations[0].coordinate.latitude, longitude: locations[0].coordinate.longitude)
let span = MKCoordinateSpan.init(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion.init(center: location, span: span)
mapView.setRegion(region, animated: true)
}
My Storyboard:
Storyboard
Code in viewDidLoad executed only once. Instead you need to check for text every time text have been changed.
To achieve this you can add view controller as UITextField delegate as described in UITextView data change swift
Quick and dirty solution would be:
#objc func klavyeyiKapat() {
view.endEditing(true)
if isimTextField.text!.isEmpty == true && notTextField.text!.isEmpty == true {
lokasyonuKaydet.isHidden = true
} else {
lokasyonuKaydet.isHidden = false
}
}
I added a new delegate UITextFieldDelegate
I made definitions in viewDidLoad
isimTextField.delegate = self
notTextField.delegate = self
I created a new function
func updateButtonVisibility() {
if isimTextField.text!.isEmpty == true && notTextField.text!.isEmpty == true {
lokasyonuKaydet.isHidden = true
} else {
lokasyonuKaydet.isHidden = false
}
}
Add delegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
updateButtonVisibility()
return true
}
Again viewDidLoad:
updateButtonVisibility()
and after these processes it started working. Please correct me if i have mistakes

Swift Using NotificationCenter to Pass Data Between View Controllers

I am trying to pass the data of user-input coordinates from one VC to another using Notifications. When I run the code, it does not add an annotation onto the MapView, so I have a hunch I may have not set up the notification to send with the inputted coordinates properly, but I am not sure where I have went wrong.
Class file that takes the input of coordinates:
import UIKit
import CoreLocation
var locations: [Dictionary<String, Any>] = [] // here I initialize my empty array of locations
class OtherVC: UIViewController {
#IBOutlet weak var latitudeField: UITextField!
#IBOutlet weak var longitudeField: UITextField!
#IBOutlet weak var titleTextField: UITextField!
var coordinates = [CLLocationCoordinate2D]()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addToMap(_ sender: Any) {
let lat = latitudeField.text!
let long = longitudeField.text!
let title = titleTextField.text!
var location: [String: Any] = ["title": title, "latitude": lat, "longitude": long]
locations.append(location)
NotificationCenter.default.post(name: NSNotification.Name("MapViewController.coordinate.updated"), object: locations, userInfo: nil)
}
}
Class file that receives notification and places annotation:
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
func add(notification: NSNotification) {
let dict = notification.object as! NSDictionary
// takes the coordinates from the notification and converts such that the map can interpret them
let momentaryLat = (dict["latitude"] as! NSString).doubleValue
let momentaryLong = (dict["longitude"] as! NSString).doubleValue
let annotation = MKPointAnnotation()
annotation.title = dict["title"] as? String
annotation.coordinate = CLLocationCoordinate2D(latitude: momentaryLat as CLLocationDegrees, longitude: momentaryLong as CLLocationDegrees)
mapView.addAnnotation(annotation)
self.mapView.centerCoordinate = annotation.coordinate
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "pinAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
}
annotationView?.annotation = annotation
return annotationView
}
}
It's the same as the Objective-C API, but uses Swift's syntax.
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(batteryLevelChanged),
name: UIDeviceBatteryLevelDidChangeNotification,
object: nil)
Or in Swift 3:
NotificationCenter.default.addObserver(
self,
selector: #selector(self.batteryLevelChanged),
name: .UIDeviceBatteryLevelDidChange,
object: nil)
If your observer does not inherit from an Objective-C object, you must prefix your method with #objc in order to use it as a selector.
#objc func batteryLevelChanged(notification: NSNotification){
//do stuff
}
Register obeserver to receive notification in your MapViewController
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.add(_:)), name: NSNotification.Name("MapViewController.coordinate.updated"), object: nil)
}
Also you can send data using userInfo property of NSNotification or send using custom object.
func add(_ notification: NSNotification) {
...
}
see pass data using nsnotificationcenter

Swift- segue between views with map annotation button

I relatively new to programming and need help switching between views by tapping a button in a mapView annotated pin.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
//REF
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var bottompnl: UIImageView!
#IBAction func mysticsbtn(sender: AnyObject) {
}
#IBAction func bondibtn(sender: AnyObject) {
}
//MAP
let locationManager = CLLocationManager()
//Annotation
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let identifier = "beach"
if annotation is Beach {
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
let btn = UIButton(type: .DetailDisclosure)
annotationView!.rightCalloutAccessoryView = btn
} else {
annotationView!.annotation = annotation
}
return annotationView
self.performSegueWithIdentifier("mysticssegue", sender: nil)
}
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
let annotations = getMapAnnotations()
// Add mappoints to Map
mapView.addAnnotations(annotations)
mapView.delegate = self
//MAP
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
//MAKES THE DOT
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MAP: Location Delegates Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let centre = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: centre, span: MKCoordinateSpan(latitudeDelta: 3, longitudeDelta: 3))
self.mapView.setRegion(region, animated: true)
self.locationManager.startUpdatingLocation()
}
//TO FIND ERROS
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Erros: " + error.localizedDescription)
}
//MARK:- Annotations
func getMapAnnotations() -> [Beach] {
var annotations:Array = [Beach]()
//load plist file
var beaches: NSArray?
if let path = NSBundle.mainBundle().pathForResource("beaches", ofType: "plist") {
beaches = NSArray(contentsOfFile: path)
}
if let items = beaches {
for item in items {
let lat = item.valueForKey("lat") as! Double
let long = item.valueForKey("long")as! Double
let annotation = Beach(latitude: lat, longitude: long)
annotation.title = item.valueForKey("title") as? String
annotations.append(annotation)
}
}
return annotations
}
//END
}
It looks like you're returning from the function mapView before calling performSegueWithIdentifier.
return annotationView
self.performSegueWithIdentifier("mysticssegue", sender: nil)
Try reversing the order of these two lines. I also noticed that you have some #IBAction methods that have no code in them.

iOS Swift delegates

I'm very new to Swift, and I'm having trouble using delegates. When the user taps on a table row in AdminAddCatTableViewController, I want to drop a pin on the map at the user's current location in AdminViewController, and I'm trying to do this using a delegate. Obviously there's something wrong with my code, as the pin does not get dropped.
In AdminAddCatTableViewController, I have
import UIKit
import Firebase
protocol AddCatDelegate: class {
func addPin(sender: AdminAddCatTableViewController)
}
class AdminAddCatTableViewController: UITableViewController {
weak var delegate:AddCatDelegate?
let admin = "secret-number"
let ref = Firebase(url: "firease_url")
#IBOutlet weak var snowballGPSLabel: UILabel!
#IBOutlet weak var smokeyGPSLabel: UILabel!
#IBOutlet weak var shadowGPSLabel: UILabel!
#IBOutlet weak var spotsGPSLabel: UILabel!
#IBOutlet weak var sunnyGPSLabel: UILabel!
var catRefArray: [AnyObject] = []
var coord:String = ""
let shareData = ShareData.sharedInstance
func updateCoord() {
if let bar = self.shareData.someString {
self.coord = bar
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "updateCoord", userInfo: nil, repeats: true)
var catNameArray: [AnyObject] = []
catNameArray.append("Snowball")
catNameArray.append("Smokey")
catNameArray.append("Shadow")
catNameArray.append("Spots")
catNameArray.append("Sunny")
for i in 0...4 {
catRefArray.append(self.ref.childByAppendingPath("admin").childByAppendingPath(self.admin).childByAppendingPath(catNameArray[i] as! String))
}
catRefArray[0].observeEventType(.Value, withBlock: { snapshot in
if let value:String = snapshot.value as? String {
self.snowballGPSLabel.text = value
}
}, withCancelBlock: { error in
print(error.description)
// same for the other rows
})
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row == 0) {
let ref0 = self.ref.childByAppendingPath("admin").childByAppendingPath(self.admin)
ref0.updateChildValues(["Snowball": self.coord])
delegate?.addPin(self)
}
// same for other rows
}
In AdminViewController, I have
import UIKit
import MapKit
import CoreLocation
class AdminViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBAction func logOutDidTouch(sender: AnyObject) {
performSegueWithIdentifier("adminToLogin", sender: self)
}
#IBOutlet weak var mapView: MKMapView!
var locationManager: CLLocationManager!
var previousLocation : CLLocation!
var latitude = 0.0;
var longitude = 0.0;
//Declare Class Variable
let shareData = ShareData.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
//On loading the screen the map kit view is shown and the current location is found and is being updated.
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.delegate = self;
let status = CLLocationManager.authorizationStatus()
if status == .NotDetermined || status == .Denied || status == .AuthorizedWhenInUse {
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
mapView.delegate = self
mapView.showsUserLocation = true
mapView.mapType = MKMapType(rawValue: 0)!
mapView.userTrackingMode = MKUserTrackingMode(rawValue: 2)!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
mapView.mapType = MKMapType(rawValue: 0)!
}
override func viewWillAppear(animated: Bool) {
//updates the location
locationManager.startUpdatingHeading()
locationManager.startUpdatingLocation()
}
override func viewWillDisappear(animated: Bool) {
locationManager.stopUpdatingHeading()
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
self.latitude = newLocation.coordinate.latitude
self.longitude = newLocation.coordinate.longitude
self.shareData.someString = "\(self.latitude)" + "," + "\(self.longitude)"
print(self.shareData.someString)
}
}
extension AdminViewController: AddCatDelegate {
func addPin(sender:AdminAddCatTableViewController) {
// drop a pin
self.mapView.delegate = self
let coordinate = mapView.userLocation.coordinate
let dropPin = MKPointAnnotation()
dropPin.coordinate = coordinate
dropPin.title = "Cat"
mapView.addAnnotation(dropPin)
}
}
Well you are never setting the delegate on your AdminAddCatTableViewController, so it is always nil and never called.
Why do you even have an extension of AdminViewController? Just remove the extension and make AdminViewController implement the delegate. To set the delegate implement something like this in your AdminViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
if segue.identifier == "YourSegueIdentifier" {
if let vc = segue.destinationViewController as? AdminAddCatTableViewController {
vc.delegate = self
}
}
}

-swift- trouble passing parse object from map kit annotation to detailViewController using disclosure button in swift

Please help, Im having trouble passing parse object from annotation Query to destinationViewController. When the user taps the annotation view it takes the user to the destinationVC, but it passes the same object no matter which annotation the user taps. I think it has something to do with the prepareForSegue function. Please let me know what Im doing wrong.
Heres my code:
class MapSearchViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var jobPosts = [PFObject]()
var jobPost: PFObject?
let locationManager = CLLocationManager()
var currentLoc: PFGeoPoint! = PFGeoPoint()
override func viewDidLoad() {
super.viewDidLoad()
//MARK new added code Start--
self.mapView.delegate = self
self.mapView.setUserTrackingMode(MKUserTrackingMode.Follow, animated: true)
//MARK new added code End--
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
//Snippet For Blue Current Location Dot:
//self.mapView.showsUserLocation = true
}
//MARK: -- Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Errors: " + error.localizedDescription)
}
//MARK: OCT 26
override func viewDidAppear(animated: Bool) {
let annotationQuery = PFQuery(className: "JobPost")
currentLoc = PFGeoPoint(location: locationManager.location)
annotationQuery.whereKey("location", nearGeoPoint: currentLoc, withinMiles: 100)
annotationQuery.findObjectsInBackgroundWithBlock {
(posts, error) -> Void in
if error == nil {
// The find succeeded.
print("Successful query for annotations")
let jobPosts = posts as [PFObject]!
for post in jobPosts {
let point = post["location"] as! PFGeoPoint
var annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
self.mapView.addAnnotation(annotation)
annotation.title = post["job"] as! String
let pay = post["price"] as! String
let payLabel = "\(pay)$"
annotation.subtitle = payLabel
let btn = UIButton(type: .DetailDisclosure)
self.jobPost = post
}
} else {
// Log details of the failure
print("Error: \(error)")
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var view = mapView.dequeueReusableAnnotationViewWithIdentifier("annotationIdentifier")
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "annotationIdentifier")
view?.canShowCallout = true
view?.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
} else {
view?.annotation = annotation
}
return view
}
var selectedAnnotation: MKPointAnnotation!
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
selectedAnnotation = view.annotation as? MKPointAnnotation
performSegueWithIdentifier("annotationSender", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destination = segue.destinationViewController as? JobDetailViewController {
destination.currentObject = jobPost
}
}
}
code for detailVC:
class JobDetailViewController: UIViewController, MFMailComposeViewControllerDelegate {
#IBOutlet weak var jobTitleLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
#IBOutlet weak var jobDescriptionContent: UITextView!
#IBOutlet weak var pictureImageView: UIImageView!
var jobPosts:[PFObject]!
var currentObject : PFObject?
var distance = "7"
var annotation = MKPointAnnotation()
override func viewDidLoad() {
super.viewDidLoad()
self.distanceLabel.text = "\(distance) miles away"
if let object = currentObject {
jobTitleLabel.text = object["job"] as! String
priceLabel.text = object["price"] as! String
jobDescriptionContent.text = object["description"] as! String
}
}