0

I am developing a small map application and I wish to have a button which removes all pins (memories) dropped to the map.

I have this code so far for managing location:

// Location function
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: 0.004, longitudeDelta: 0.004))
    self.placesMap?.setRegion(region, animated: true)
    self.locationManager.stopUpdatingLocation()
    let locationDictionary:[String:Double] = ["latitude":center.latitude,"longitude":center.longitude]
    var locationArray = [[String:Double]]()
    if NSUserDefaults.standardUserDefaults().objectForKey("locationArray") != nil {
        locationArray = NSUserDefaults.standardUserDefaults().objectForKey("locationArray") as! [[String:Double]]
    }
    locationArray.append(locationDictionary)
    NSUserDefaults.standardUserDefaults().setObject(locationArray, forKey: "locationArray")
    NSUserDefaults.standardUserDefaults().synchronize()
}

func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
    print("Error code: " + error.localizedDescription)
}

Here is the button to drop a pin:

@IBOutlet weak var addButton: UIBarButtonItem!
@IBAction func addButton(sender: AnyObject) {
    let annotation = MKPointAnnotation()
    annotation.coordinate = CLLocationCoordinate2D(latitude: self.placesMap.userLocation.coordinate.latitude, longitude: self.placesMap.userLocation.coordinate.longitude)
    self.placesMap.addAnnotation(annotation)
    self.locationManager.startUpdatingLocation()
}

Here is outlet / action to reset the pins:

@IBAction func resetMemories(sender: AnyObject) {
    func removeStoredLocations(){
        NSUserDefaults.standardUserDefaults().removeObjectForKey("locationArray")
        NSUserDefaults.standardUserDefaults().synchronize()
        placesMap.removeAnnotations(placesMap.annotations)
    }
}

When I press the button currently no error occours, but the pins still remain on the map :(

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Oscar
  • 511
  • 2
  • 10
  • 25

2 Answers2

2

In your resetMemories IBAction you created a nested function removeStoredLocations. Then you never call that nested function, so the code never gets executed. I would suggest getting rid of the nested function:

@IBAction func resetMemories(sender: AnyObject) 
{          
  NSUserDefaults.standardUserDefaults().removeObjectForKey("locationArray")
  NSUserDefaults.standardUserDefaults().synchronize()
  let annotationsToRemove = placesMap.annotations.filter 
  { 
    $0 !==  placesMap.userLocation 
  }
  placesMap.removeAnnotations( annotationsToRemove )
}

Or, if you really want a nested function, you have to call it:

@IBAction func resetMemories(sender: AnyObject) 
{
  //Define our local function removeStoredLocations().
  func removeStoredLocations()    
  {          
    NSUserDefaults.standardUserDefaults().removeObjectForKey("locationArray")
    NSUserDefaults.standardUserDefaults().synchronize()
    let annotationsToRemove = placesMap.annotations.filter 
    { 
      $0 !==  placesMap.userLocation 
    }
    placesMap.removeAnnotations( annotationsToRemove )
  }

  //Now that we've defined our local function, call it.
  removeStoredLocations()
}

EDIT:

Jthomps is right. You should use his code that does not remove the annotation for the user location. I am editing my code above to incorporate his.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks for your answer. I get the same error as I get with Jthomps answer, it is because the button is present on a new scene I think. Have you got any other suggestions to help get this working? – Oscar Apr 24 '16 at 16:04
  • "...it is because the button is present on a new scene I think." Huh? You think it's on a new scene, or you think that's why you're having problems? You need to edit your question and provide a LOT more information if we are going to have any chance of helping you. As it is I'm voting to put your question on hold. – Duncan C Apr 24 '16 at 19:50
0

I have removed the nested function that you had within the outlet. That's why it was never getting called in the first place.

Try changing to this code snippet :

@IBAction func resetMemories(sender: AnyObject) {

        NSUserDefaults.standardUserDefaults().removeObjectForKey("locationArray")
        NSUserDefaults.standardUserDefaults().synchronize()
        let annotationsToRemove = placesMap.annotations.filter { $0 !== placesMap.userLocation }
        placesMap.removeAnnotations(annotationsToRemove)
}
Jonathan Eustace
  • 2,469
  • 12
  • 31
  • 54
  • 1
    Good point about not removing the user location annotation. (Voted.) – Duncan C Apr 24 '16 at 14:40
  • Note that the OP was using a nested function that he never called. It's important to point that out. – Duncan C Apr 24 '16 at 14:41
  • Thanks for your reply, I tried this but now I get an error (EXC_BAD_INSTRUCTION) on the "let annotation" line when the button is pressed :( – Oscar Apr 24 '16 at 14:41
  • All I can see is the EXC_BAD_INSTRUCTION error message on that line? – Oscar Apr 24 '16 at 14:45
  • There should be some output in the console that would describe the error a little more. – Jonathan Eustace Apr 24 '16 at 14:45
  • Yes sorry, my mistake. In the console it states "fatal error: unexpectedly found nil while unwrapping an Optional value" – Oscar Apr 24 '16 at 14:47
  • Before you clicked the button, were there annotations populated on the map? – Jonathan Eustace Apr 24 '16 at 14:47
  • Yes there were, although I noticed when implementing your code the previously existing ones were erased even before pressing the button – Oscar Apr 24 '16 at 14:49
  • Are you calling resetMemories anywhere else in the code? Change the signature of the method to : `@IBAction func resetMemories(sender: UIButton)` As only a button should be calling this function (from what I understand of your desired functionality) – Jonathan Eustace Apr 24 '16 at 14:50
  • No I am not, I changed the signature of the method but still the same error persists. I have the reset button on a new scene which is presented modally. They are members of the same class though, but could it be because of this? – Oscar Apr 24 '16 at 14:57
  • I think that's why you're getting this error. Try running it within the same scene. – Jonathan Eustace Apr 24 '16 at 15:01
  • Is there any way to get this to function via the new scene? I dont have space to put a button on the same scene :( Just dragged the button to the same scene and tried, no error but still no pins are removed – Oscar Apr 24 '16 at 15:02
  • You would have to pass the map as a variable into the new scene in order for this to work. I would also make sure that you're not accidentally repopulating the map from an array after clicking the reset button. – Jonathan Eustace Apr 24 '16 at 15:16
  • Could you post an example of how to do this? I am new to Swift so it is hard for me to understand. Thanks for all your help so far though – Oscar Apr 24 '16 at 15:17
  • 1
    Take a look at this link on how to pass data into a segue. http://stackoverflow.com/questions/26207846/pass-data-through-segue – Jonathan Eustace Apr 24 '16 at 15:19