1

У меня было несколько прошлых впечатлений, используя MKMapView и MKPointAnnotation, которые я использовал, чтобы поместить некоторый вывод на карту. На этот раз я пытаюсь сделать еще один шаг и использовать MKPinAnnotationView, чтобы написать ярлык вместе с некоторыми выводами.Как обновить информацию о MKPinAnnotationView?

К сожалению, это не все работает так, как я ожидаю.

Вот что я хочу сделать:

У меня есть карта (объект MKMapView), и когда я касаюсь его, я положил палец на точках касания, то некоторые вычисления производятся, и это дает мне вторая точка на карте. Я положил второй вывод на карту (расположенный во второй точке), на этом последнем булавке я хочу поставить ярлык, скажем, «Hello Second!», Но этот ярлык нужно обновлять, когда меняется контакт.

Вот соответствующий код:

class ViewController: UIViewController, MKMapViewDelegate { 
    var mapView:MKMapView!, touchPoint,secondPoint:MKPointAnnotation! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     mapView = MKMapView() 
     ........... 
     let mapTap = UITapGestureRecognizer(target: self, 
              action: #selector(ViewController.mapTouchHandler)) 
     mapView.addGestureRecognizer(mapTap) 
    } 


    func mapTouchHandler(gesture:UITapGestureRecognizer) { 
     ........... 
     // Compute map coordinates for the touch point (tapGeoPoint). 

     if touchPoint == nil { 
      touchPoint = MKPointAnnotation() 
      mapView.addAnnotation(touchPoint); 
     } 

     touchPoint.coordinate = CLLocationCoordinate2D(latitude: tapGeoPoint.latitude, 
                 longitude: tapGeoPoint.longitude) 
     ........... 
     computeSecondPoint(url: someComputedURL) 
    } 


    func computeSecondPoint(url searchURL:String) { 
     let reqURL = NSURL(string: searchURL)!, session = URLSession.shared, 
     task = session.dataTask(with: reqURL as URL) { 
      (data: Data?, response: URLResponse?, error: Error?) in 
      if error == nil { 
       do {let allData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSArray 
        ................. 
        // Compute map coordinates for the second point (secondPointCoord). 

        if self.secondPoint == nil { 
         self.secondPoint = MKPointAnnotation() 
         self.mapView.addAnnotation(self.secondPoint) 
        } 

        DispatchQueue.main.async { 
         () -> Void in 
         self.secondPoint.coordinate = CLLocationCoordinate2D(latitude: secondPointCoord.latitude, 
                      longitude: secondPointCoord.longitude) 
         self.secondPoint.title = "Hello Second -TITLE!" 
         //* I want to update the label for this pin (attached to the secondPoint) too. 
        } 
       } catch let error as NSError {print(error.localizedDescription)} 
      } else { 
       print("Error inside \(#function):\n\(error)") 
      } 
     } 

     task.resume() 

    } 


    func mapView(_ mapView: MKMapView, 
       viewFor annotation: MKAnnotation) -> MKAnnotationView? { 
     let identifier = "pin" 
     var view: MyPinAnnotationView 
     if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) 
      as? MyPinAnnotationView { 
      dequeuedView.annotation = annotation 
      view = dequeuedView 
     } else { 
      view = MyPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) 

      if ((annotation.coordinate.latitude != touchPoint.coordinate.latitude) || 
       (annotation.coordinate.longitude != touchPoint.coordinate.longitude)) {//* I need a better test to check that this not touchPoint! 
       view.pinTintColor = UIColor.blue 
       view.canShowCallout = true 
       view.calloutOffset = CGPoint(x: -7, y: 0) 
       view.setInfo(title: "Hi Start Label!") 
      } else { 
       view.pinTintColor = UIColor.red 
       view.canShowCallout = false 
      } 
     } 
     return view 
    } 
} 

Вот класс MyPinAnnotationView:

import UIKit 
import MapKit 

class MyPinAnnotationView: MKPinAnnotationView { 
    let information:UILabel = UILabel(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 70.0, height: 30.0))) 

    func setInfo(title : String) 
    { 
     information.text = title 
     information.textAlignment = .center 
     self.addSubview(information) 
    } 


    func hideInfo() { 
     information.removeFromSuperview() 
    } 
} 

Линии с комментарием отмечены // *, шоу, где мне нужна помощь.

  • Первый выпуск, я хочу обновить ярлык во втором пункте, но я не знаю, какой код использовать. Строка:

    // * Я хочу обновить метку для этого вывода (также прилагается к второму пункту).

Теперь ярлык отображается как первый набор, но я не знаю, как его обновить.

  • Вторая проблема, должен быть лучший способ проверить, с каким контактом я имею дело. Линия:

    // * Мне нужен лучший тест, чтобы проверить, что это не touchPoint!

+0

Вы поделитесь своим демо, если вы не возражаете? Я могу понять вашу проблему и ответить на нее –

+0

Хорошо, но дайте мне знать, что вам нужно знать, что не в моем посте. Я уже поделился всем, о чем я могу думать по этому вопросу, здесь, в сообщении. – Michel

+0

проверить этот ответ Я думаю, что это поможет вам http://stackoverflow.com/questions/24467408/swift-add-mkannotationview-to-mkmapview –

ответ

1

Если вы хотите, чтобы в аннотационном представлении отображался текст, который обновляется как изменения аннотации, используйте KVO в аннотации. Итак, во-первых, создать объект модели, аннотацию, которая включает в себя новое свойство необходимо соблюдать:

class MyAnnotation: NSObject, MKAnnotation { 
    dynamic var title: String? 
    dynamic var subtitle: String? 
    dynamic var coordinate: CLLocationCoordinate2D 
    dynamic var information: String? 

    init(title: String? = nil, subtitle: String? = nil, coordinate: CLLocationCoordinate2D, information: String? = nil) { 
     self.title = title 
     self.subtitle = subtitle 
     self.coordinate = coordinate 
     self.information = information 
    } 
} 

Я назвал это новое свойство information, но вы, вероятно, можете придумать лучшее название, которое захватывает функциональное намерение этого свойства. Но, надеюсь, это иллюстрирует эту идею. Ключевым выводом здесь является то, что если это свойство может измениться в более поздней точке, мы хотим сделать его dynamic, чтобы мы могли использовать KVO для наблюдения за этими изменениями.

class MyPinAnnotationView: MKPinAnnotationView { 
    private let informationLabel = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 70.0, height: 30.0))) 

    private var observerContext = 0 

    override var annotation: MKAnnotation? { 
     willSet { 
      removeObserverIfAny() 
     } 
     didSet { 
      if let annotation = annotation as? MyAnnotation { 
       annotation.addObserver(self, forKeyPath: #keyPath(MyAnnotation.information), context: &observerContext) 
       informationLabel.text = annotation.information 
      } 
     } 
    } 

    deinit { 
     removeObserverIfAny() 
    } 

    private func removeObserverIfAny() { 
     if let oldAnnotation = annotation as? MyAnnotation { 
      oldAnnotation.removeObserver(self, forKeyPath: #keyPath(MyAnnotation.information)) 
     } 
    } 

    func showInformation() { 
     addSubview(informationLabel) 
    } 

    func hideInformation() { 
     informationLabel.removeFromSuperview() 
    } 

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
     guard context == &observerContext else { 
      super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 
      return 
     } 

     if let annotation = annotation as? MyAnnotation, let information = annotation.information { 
      informationLabel.text = information 
     } 
    } 

} 

extension ViewController: MKMapViewDelegate { 
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { 
     if annotation is MKUserLocation { return nil } 

     var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MyPinAnnotationView 
     if annotationView == nil { 
      annotationView = MyPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) 
      annotationView?.canShowCallout = true 
     } else { 
      annotationView?.annotation = annotation 
     } 
     annotationView?.showInformation() 
     return annotationView 
    } 
} 

Я изменил имя метки для informationLabel, чтобы сделать его немного более ясно, что это точка зрения, не следует путать со свойством модели, information, нашего нового MyAnnotation класса. Кроме того, я бы предложил более значимые имена классов, чем MyAnnotation и MyPinAnnotationView, возможно, используя какое-то имя, которое лучше отражает функциональное назначение этих двух классов.

Независимо от того, как вы можете видеть, когда вы устанавливаете annotation для этого аннотационного просмотра, он обновляет метку text. Но он также замечает новое свойство information аннотации через KVO, поэтому, если это свойство изменится позже, представление обновится соответствующим образом.

+0

Нет, я не хочу наблюдать за званием по причине, о которой вы говорили. Но я буду помнить о вашей идее наблюдателя и посмотреть, смогу ли я с ней что-то сделать. Я хочу обновить информацию UILabel (см. Мой пост). – Michel

+0

Мне, безусловно, нужно работать, начиная с вашей идеи. Я должен сказать, просто прочитав ваш код, я не очень понимаю на данный момент. В конце концов, я хочу обновить содержимое информации (UILabel), когда пользователь коснется экрана и места изменения второй точки. Я надеюсь, что то, что вы предложите, позволит мне это сделать, как только я увижу, как это работает. – Michel

+0

@Michel - Да, поэтому мы используем шаблон наблюдателя, чтобы вы могли обновить некоторое свойство аннотации в более поздней точке, и представление аннотации будет соответствующим образом обновляться. Просто соблюдайте некоторые свойства, кроме 'title'. См. Мой расширенный ответ выше. – Rob