Problème de mémoire avec la carte

Luc-ALuc-A Membre
novembre 2017 modifié dans API UIKit #1

Bonjour à  tous !


 


J'ai constaté, avec mon iPhone, que la carte prenait beaucoup de mémoire lorsqu'elle était affichée un bon nombre de fois. J'ai même réussi à  saturer la mémoire de mon iPhone (1.6 gigas).


 


Donc, j'ai recherché une solution. D'après les forums, la solution serait de vider les variables qui contiennent la carte. J'ai utilisé le code suivant :



override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

applyMapViewMemoryFix()
}

func applyMapViewMemoryFix() {
mapView.showsUserLocation = false
mapView.delegate = nil
mapView.removeFromSuperview()
mapView = nil
}

Le problème de mémoire est moins présent, mais il persiste.


 


Il y a cependant une autre solution : créer une instance de mapKit. C'est une bonne idée : la carte sera enregistrer dans la mémoire une fois pour toute.


Cependant, je vous avoue que je ne vois pas du tout comment faire... Je ne vois pas comment je pourrai créer la carte de manière à  ce qu'elle soit enregistrer une et une seule fois dans la mémoire.


 


Je vous remercie pour votre aide !


Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    Tu peux nous montrer le code pour le var et le code qui crée la MKMapView
  • Luc-ALuc-A Membre
    novembre 2017 modifié #3

    Voici le code qui créé la MKMapView :



    class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UIGestureRecognizerDelegate, AddAnnotationDelegate, RemoveAnnotationDelegate {

    let locationManager: CLLocationManager = CLLocationManager()
    var delta: Double = 0.01
    var annotation: [Annotation]?
    var thisAnnotation: Annotation?
    var index: Int?
    var lat: CLLocationDegrees = 0
    var lng: CLLocationDegrees = 0

    var pinAnnotationView:MKPinAnnotationView!

    @IBOutlet weak var mapView: MKMapView!

    private let db = DataBase()
    private let preferences = Preferences()
    private let location = Location()
    private let model = ModelController()

    override func viewDidLoad() {
    super.viewDidLoad()

    mapView.delegate = self

    let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.addAnnotation(gestureReconizer:)))
    gestureRecognizer.delegate = self
    mapView.addGestureRecognizer(gestureRecognizer)

    initMap()
    }

    override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    showAnnotation()
    updateNavigationControllers()
    }

    override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    applyMapViewMemoryFix()
    }

    func applyMapViewMemoryFix() {
    mapView.showsUserLocation = false
    mapView.delegate = nil
    mapView.removeFromSuperview()
    mapView = nil
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch segue.identifier! {
    case "ListAnnotation":
    let destination = segue.destination as! ListAnnotationTableViewController
    destination.annotation = annotation!

    case "AddAnnotation":
    let destination = segue.destination as! AddAnnotationViewController
    destination.lat = lat
    destination.lng = lng
    destination.delegate = self

    case "showDetails":
    let destination = segue.destination as! DetailsAnnotationViewController
    destination.annotation = annotation!
    destination.thisAnnotation = sender! as? Annotation
    destination.delegate = self
    destination.index = index!

    default:
    break
    }
    }

    // MARK: - IBActions

    @IBAction func addPin(_ sender: Any) { //AddAnnotation
    guard lat != 0 && lng != 0 else { return }
    }

    // MARK: - Delegate

    func addAnnotation(annotation: Annotation) {
    self.annotation!.append(annotation)
    }

    func removeAnnotation(annotation: Annotation) {
    var index: Int = 0

    for i in 0..<self.annotation!.count {
    if self.annotation?[i].id == annotation.id {
    index = i
    break
    }
    }
    self.annotation?.remove(at: index)
    mapView.removeAnnotations(mapView.annotations)
    }

    // MARK: - Functions

    func initMap() {

    let span = MKCoordinateSpan(latitudeDelta: delta, longitudeDelta: delta)

    if CLLocationManager.locationServicesEnabled() {

    // Coordonnées de l'utilisateur
    mapView.mapType = MKMapType.standard
    mapView.showsUserLocation = true

    if lat == 0 {
    lat = (locationManager.location?.coordinate.latitude)!
    lng = (locationManager.location?.coordinate.longitude)!
    }

    // Coordonnées de la région
    let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
    let region = MKCoordinateRegionMake(location, span)

    mapView.setRegion(region, animated: true)
    }
    }

    //MARK: - Annotation

    @objc func addAnnotation(gestureReconizer: UITapGestureRecognizer) {
    let location = gestureReconizer.location(in: mapView)
    let coordinate = mapView.convert(location,toCoordinateFrom: mapView)

    let annotation = CustomPointAnnotation()
    annotation.coordinate = coordinate

    lat = annotation.coordinate.latitude
    lng = annotation.coordinate.longitude
    }

    func showAnnotation() {
    for i in 0..<annotation!.count {
    let lat = annotation![i].lat
    let lng = annotation![i].lng
    let title = annotation![i].title
    let favorites = annotation![i].favorites
    let pinLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
    let position = location.distance(of: Position.init(lat: lat, lng: lng))
    let pointAnnotation = CustomPointAnnotation()
    pointAnnotation.coordinate = pinLocation
    pointAnnotation.title = title
    pointAnnotation.subtitle = model.calculateDistance(distance: position)
    if favorites {
    pointAnnotation.imageName = "PinsFav" // "DrapOrange"
    } else {
    pointAnnotation.imageName = "Pins" // "DrapBlue"
    }
    pinAnnotationView = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: "pin")
    mapView.addAnnotation(pinAnnotationView.annotation!)
    }
    }

    //MARK: - Custom Annotation
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation.isKind(of: MKUserLocation.self) { return nil }
    if !(annotation is CustomPointAnnotation) { return nil }

    let reuseIdentifier = "pin"
    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)

    if annotationView == nil {
    annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
    annotationView?.canShowCallout = true
    } else {
    annotationView?.annotation = annotation
    }

    let pin = annotation as! CustomPointAnnotation
    annotationView?.image = UIImage(named: pin.imageName)

    annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

    return annotationView
    }

    func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    for i in 0..<annotation!.count {
    if view.annotation?.title! == annotation![i].title {
    index = i
    }
    }

    if control == view.rightCalloutAccessoryView {
    performSegue(withIdentifier: "showDetails", sender: annotation![index!])
    }
    }

        
        // MARK: - Navigation
        
        private func updateNavigationControllers() {
            switch navigationController!.viewControllers.count {
            case 3:
                navigationController!.viewControllers.remove(at: 1)
                
            case 4:
                let viewControllerFirst = navigationController?.viewControllers.first
                let viewControllerLast = navigationController?.viewControllers.last
                navigationController?.viewControllers = [viewControllerFirst!, viewControllerLast!]
                
            default:
                break
            }
        }
    }

    Le code pour le var ??


  • Joanna CarterJoanna Carter Membre, Modérateur

    Que fais-tu en updateNavigationControllers() ?


  • Désolé, c'est important ! Je me suis rendu compte que lorsque l'utilisateur allait sur la carte, et qu'il regardait les détails d'une annotation, et qu'il retournait sur la carte (et ainsi de suite), il y avait des clones des pages de la carte et de la page qui montre les détails des annotations. Donc, j'ai pris la liberté de supprimer les doublons en modifiant la liste des views controllers dans le navigation controller.


     


    Voilà  :



    private func updateNavigationControllers() {
    switch navigationController!.viewControllers.count {
    case 3:
    navigationController!.viewControllers.remove(at: 1)

    case 4:
    let viewControllerFirst = navigationController?.viewControllers.first
    let viewControllerLast = navigationController?.viewControllers.last
    navigationController?.viewControllers = [viewControllerFirst!, viewControllerLast!]

    default:
    break
    }
    }

    Je vais éditer le code.


  • Joanna CarterJoanna Carter Membre, Modérateur

    !!!!!!!!!!!!!!!!!!!!!!!


     


    Voilà  ! Cette sorte de bricolage ne devrait jamais être nécessaire. Tu as une une grosse faute de logique dans ton appli.


  • Je sais bien que c'est du bricolage, et je suppose qu'il faut que je change ça tout de suite !


     


    Je suppose qu'il faut que j'utilise un delegate qui va modifier les informations afficher dans la page des détails d'une annotation et que je cache la page de la carte.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Qu'est-ce que tu as comme storyboard ?


  • J'ai fait une capture d'écran.


     


    J'ai un navigation controller, une view Annotations qui contient une tableView montrant toutes les annotations, une view Map qui contient la carte, une view Annotation qui montre les détails d'une annotation et qui fait le lien entre la tableView et la carte, et une autre view, similaire à  la précédente qui permet d'ajouter une annotation.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Donc, tu as un segue de ton MapViewController vers ton AnnotationViewController que a, à  son tour, un segue vers ton MapViewController ??????


     


    Boucle infinie !!!!!


     


    Et tu as deux segues du TableViewController, l'un vers l'AnnotationViewController qui a, à  son tour, un segue vers le MapViewController ; et l'autre directement vers le MapViewController !!!


     


    Le UINavigationController gère une pile de UIViewControllers. Si tu crées une boucle, tu n'auras que des problèmes.


     


    Il faut repenser  8--)


  • Luc-ALuc-A Membre
    novembre 2017 modifié #11

    Effectivement, j'ai créé une boucle infini. Je voulais que l'application soit facile à  utiliser, mais je n'ai pas vérifier la pertinence du code !


     


    Et j'aime bien faire très compliqué aussi !


     


    Ce que je peux faire, c'est supprimer le segue qui va de l'AnnotationViewController vers le MapViewController. Mais l'utilisateur ne pourra plus afficher la carte après avoir regardé les détails d'une annotation...


     


    Bref, il faut vraiment que je repense tout ça.


     


    Je te remercie pour ton aide, Joanna Carter !


     


    Edit : J'ai compris ! Il faut sois que j'affiche la carte directement après le UIAnnotationsViewController (la liste des annotations), suit que j'affiche le détails. Mais je ne peux pas proposer les deux. Je pense que je vais choisir la carte pour mon application.


    Et donc, l'annotationViewController sera le dernier View Controller dans le Navigation Controller.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu as pensé de ceci ?


     


  • Je te remercie beaucoup Joanna !!


     


    Je vais modifier tout ça !


  • Luc-ALuc-A Membre
    novembre 2017 modifié #14

    Joanna Carter, tu as trouvé LA solution !


     


    En effet, si la carte est directement affichée avec un tab bar controller, elle n'est chargée qu'une seule fois, et donc, il n'y a pas de souci de mémoire.


     


    Or, j'aimerai tout de même faire quelque chose qui se rapproche de ce que j'avais fait au départ.


    J'ai pensé à  une solution : au lieu de supprimer les UIViewController du Navigation Controller, je pourrai tout simplement simuler un click sur l'item de la carte ou sur un autre item pour revenir. Le problème est que je ne parviens pas, avec le code, à  récupérer la tab bar que j'ai créé dans mon storyboard. Comment faire ?


  • Draken, j'ai essayé ce que tu dis, à  savoir charger la carte en mémoire au lancement de l'application, et franchement, cette solution serait top pour moi, mais je ne sais pas comment faire...


     


    Oui, j'ai suivi une formation, mais il y a plein de choses que l'on a pas vu...


     


    Cependant, j'ai essayé de faire comme ce que tu as dit, mais je n'y suis pas parvenu...


    Pourtant, j'ai réussi à  enregistrer le UIViewController de la Map dans AppDelegate (c'est une solution que j'ai trouvé sur Internet), mais je ne sais pas du tout si c'est correct...


     


    Voici ce que j'ai fait :



    func showMap() -> UIViewController {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "MapViewController") // as! MapViewController
    return controller
    }
  • Ah non, ce n'est pas correct du tout. A chaque appel de showMap() l'application recrée une nouvelle instance de " MapViewController".


     


    Ce qu'il faut c'est créer l'objet UNE SEULE FOIS et conserver son adresse dans une variable de l'AppDelegate.

  • Luc-ALuc-A Membre
    novembre 2017 modifié #17

    Draken aurais-tu un exemple concret s'il te plait ?


     


    J'ai déjà  essayé de créer une variable dans l'AppDelegate, mais à  chaque fois, j'ai eu des crash !


     


    J'avais fait : let map = MapViewController()


     


    Et comment l'utiliser correctement avec les segues ?


     


    EDIT : J'ai compris pourquoi ça crash, mais je ne sais pas comment corriger. J'ai besoin d'accéder au context de Core Data, et donc, je l'appel sur différente page. Le souci est que je l'ai enregistré dans l'AppDelegate, et que ça crash lorsque c'est l'AppDelegate lui-même qui instancie le MapViewController.


  • DrakenDraken Membre
    novembre 2017 modifié #18


    Draken aurais-tu un exemple concret s'il te plait ?


     




     


    Petit exemple avec une UIImage chargée dans l'AppDelegate.



    import UIKit

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    // Nouvelle variable du délégué
    var monImage:UIImage?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    // Initialisation de l'image
    monImage = UIImage(named: "alienGris")
    return true
    }

    // ....
    }



    Dans un ViewController quelconque :



    import UIKit

    class ViewController: UIViewController {

    @IBOutlet weak var maVue: UIView!

    override func viewDidLoad() {
    super.viewDidLoad()

    // Lire l'image dans un ViewController
    if let image = (UIApplication.shared.delegate as? AppDelegate)?.monImage {
    print ("Taille image : ", image.size)
    // faire quelque chose avec l'image
    // ...
    }

    }
    }


    * attend stoà¯quement un commentaire de Ceroce *

  • Céroce, j'ai aussi essayé ta solution, qui correspond à  celle de Joanna Carter.


     


    J'ai effectivement mis la carte dans un UItabbar, et comme ça, elle n'est chargée qu'une seule fois. C'est très bien. Maintenant, j'aimerai pouvoir simuler le "click" de l'item de la tabbar qui correspond à  la map.


     


    Mais je ne sais pas comment faire pour récupérer les items de la tabbar que j'ai créé dans mon storyboard.


    Il me faut aussi savoir comment transmettre des données à  la map (par exemple pour centrer la map sur une annotation) et pouvoir revenir facilement, c'est-à -dire en simulant un navigation controller pour que l'utilisateur ne soit pas perdu.


     


    Draken, je te remercie pour ton exemple !


  • CéroceCéroce Membre, Modérateur

    Et comment l'utiliser correctement avec les segues ?

    On ne peut pas, une Segue sert à  définir la transition d'un ViewController à  l'autre (" segue " est un terme issu de l'opéra, qui signifie " suite " en Italien). On passe les variables d'un VC à  l'autre dans la méthode UIViewController.prepareForSegue()
     

    EDIT : J'ai compris pourquoi ça crash, mais je ne sais pas comment corriger. J'ai besoin d'accéder au context de Core Data, et donc, je l'appel sur différente page. Le souci est que je l'ai enregistré dans l'AppDelegate, et que ça crash lorsque c'est l'AppDelegate lui-même qui instancie le MapViewController.

    Une règle de la POO: "Tell, don't ask". Si l'AppDelegate instancie le ManagedObjectContext(MOC), alors c'est lui qui doit le passer au premier VC. La manière de le faire est tirée par les cheveux, mais Apple l'a prévu ainsi (de mémoire):


    class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let moc = // ManagedObjectContext

    let mapController = window.rootViewController as! MapController
    mapController.moc = moc // MapController a évidemment un propriété 'moc'

    return true
    }
    }
  • CéroceCéroce Membre, Modérateur


    if let image = (UIApplication.shared.delegate as? AppDelegate)?.monImage {
    * attend stoà¯quement un commentaire de Ceroce *

    Ainsi, tout l'application a des dépendances cachées sur l'AppDelegate. Niveau réutilisation du code, c'est un zéro pointé, M. Draken. Et je ne parle même pas de la mise en place de tests unitaires.
  • DrakenDraken Membre
    novembre 2017 modifié #22


    Ainsi, tout l'application a des dépendances cachées sur l'AppDelegate. Niveau réutilisation du code, c'est un zéro pointé, M. Draken. Et je ne parle même pas de la mise en place de tests unitaires.




    * se planque au fond de la classe, dans l'armoire à  coté du radiateur *


     


    * murmure " C'est pas moi monsieur, j'ai copié un exemple d'Apple sur l'utilisation du PersistentContainer de CoreData, par l'intermédiaire de l'AppDelegate *


  • CéroceCéroce Membre, Modérateur

    J'ai effectivement mis la carte dans un UItabbar, et comme ça, elle n'est chargée qu'une seule fois. C'est très bien. Maintenant, j'aimerai pouvoir simuler le "click" de l'item de la tabbar qui correspond à  la map.

    Pourquoi? Tu as une tabbar qui ne présente pas ses onglets à  l'utilisateurs ? Je ne connais pas l'appli, mais tout cela me semble fort étrange.
     

    Mais je ne sais pas comment faire pour récupérer les items de la tabbar que j'ai créé dans mon storyboard.

    Les joies du storyboard... " c'est plus facile que les xib, qu'y disaient ".
    Le rootViewController de la window (voir mon code plus haut) est le UITabBarController.
    On peut donc écrire un truc du style:
    let tabBarController = window.rootViewController as! UITabBarController
    let mapController = tabBarController.viewControllers[0]
    mapController.delegate = self // Disons self (l'AppDelegate), mais on peut aussi avoir une autre classe qui se charge de ça
    Dans cette solution, il y a un objet plus haut dans la hiérarchie qui peut accéder aux deux VC, et qui peut se mettre en délégué des deux pour leur retransmettre les informations.
    On encore, qui fait qu'un VC est le délégué de l'autre.

    Il me faut aussi savoir comment transmettre des données à  la map (par exemple pour centrer la map sur une annotation) et pouvoir revenir facilement, c'est-à -dire en simulant un navigation controller pour que l'utilisateur ne soit pas perdu.

    Il me semble que la solution est plutôt de ne pas utiliser un UITabBarController, mais un UINavigationController, et dépiler au besoin. On encore présenter le mapVC en modal.
  • CéroceCéroce Membre, Modérateur

    * murmure " C'est pas moi monsieur, j'ai copié un exemple d'Apple sur l'utilisation du PersistentContainer de CoreData, par l'intermédiaire de l'AppDelegate *

    Au moins, monsieur Draken, si vous copiez, copiez sur les bons élèves!

    (le code d'exemple d'Apple est souvent une occasion de démythifier l'ingénieur(e) d'Apple qui serait une sorte de surhumain.)
  • Je crois que je suis en train d'essayer de faire quelque chose d'impossible à  faire.


     


    Ce que je voulais faire, c'est créer un UIViewController avec une carte, le garder en mémoire et l'afficher lorsque je voudrais. Or,il semble que c'est simplement impossible, et surtout, contraire à  toutes les règles de la POO.


     


    Ce que je pourrai faire, c'est mettre la carte en premier.


     


    Céroce, j'avais comme ce que tu as dit, avec un UINavigationController (et pas avec un UITabbarController), et comme Joanna Carter l'a dit, j'ai fait du bricolage en supprimant avec le code les UIViewController qui étaient en double dans le UINavigationController.


     


    Le problème reste la mémoire, car à  chaque fois que la carte est affcihée, l'application utilise de plus en plus la RAM. Et je ne sais pas du tout mais j'espère apprendre très vite à  gérer la mémoire utilisée par mes applications.


     


    Céroce, je te remercie pour toutes tes explications !


    Je pense que je vais suivre ma dernière idée, et mettre la carte en premier dans le UINavigationController, comme ça, la carte ne sera chargée qu'une seule fois et je pourrai proposer à  l'utilisateur la navigation que j'ai prévu initialement.


     


    Je vous remercie pour votre aide !


  • CéroceCéroce Membre, Modérateur
    novembre 2017 modifié #26

    Ce que je voulais faire, c'est créer un UIViewController avec une carte, le garder en mémoire et l'afficher lorsque je voudrais. Or,il semble que c'est simplement impossible, et surtout, contraire à  toutes les règles de la POO.



    Si c'est possible, d'ailleurs c'est ce qui se passe quand tu as un UITabBarController: il retient les VC qu'il affiche. Pareil quand un tu as un UINavigationController: les VC empilés dessus sont retenus.



    Ton problème est justement que tu empiles à  chaque fois une nouvelle instance, donc au bout d'un moment, forcément, ça prend beaucoup de mémoire. Il faut dépiler, pour réutiliser l'instance existante.


  • Luc-ALuc-A Membre
    novembre 2017 modifié #27

    Je te remercie Céroce, mais je ne sais pas comment faire.


    J'ai bien compris comment fonctionne le Segue, même si je n'ai pas encore tout utiliser, comme modal par exemple.


     


    Oui, le problème est que je créé une nouvelle instance à  chaque fois.


     


    Lorsque j'utilise dismiss, ou que je tape sur le bouton retour d'un UINavigationController, je suppose que les UIViewController sont supprimé de la mémoire. La question est de savoir comment cacher et afficher un UIViewController dans une UINavigationController sans instancier ledit UIViewController.


     


    Je crois que je sais ce que je pourrai faire : instancier la mapViewController dans l'AppDelegate, et créer des segue avec le code, sans passer par le storyboard.


     


    Voici ce que j'ai fait dans AppDelegate :



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    map = storyboard.instantiateViewController(withIdentifier: "MapViewController") as! MapViewController

    return true
    }

    Et dans un UIViewController :



    @IBAction func afficherCarte() {
    let view = appDelegate.map! as! MapViewController
    view.annotation = annotation
    show(view, sender: nil)
    }

    J'aurai du utiliser PerformSegue de manière à  caster plus facilement la view.


    Est-ce correct Céroce ??


  • Joanna CarterJoanna Carter Membre, Modérateur
    novembre 2017 modifié #28

    Pour ton problème de changer le tab vers la carte, il faut créer une notification et une classe pour le Tab Bar Controller :



    extension Notification.Name
    {
    static let mapRequested = Notification.Name("mapRequested")
    }


    class TabBarController : UITabBarController
    {
    weak var mapNavigationController: UINavigationController?

    required init?(coder aDecoder: NSCoder)
    {
    super.init(coder: aDecoder)

    NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.observeMapRequest), name: .mapRequested, object: nil)
    }

    override func viewDidLoad()
    {
    super.viewDidLoad()

    guard let mapNavigationController = viewControllers?.first(where:
    {
    guard let navigationController = $0 as? UINavigationController else
    {
    return false
    }

    return navigationController.topViewController is MapViewController
    }) as? UINavigationController else
    {
    return
    }

    self.mapNavigationController = mapNavigationController
    }

    @objc func observeMapRequest(notification: Notification)
    {
    self.selectedViewController = mapNavigationController
    }
    }

    Puis, dans la classe pour la liste des annotations, il faut lier un bouton à  une action avec le code suivant :



    class AnnotationsViewController: UITableViewController
    {
    @IBAction func changeToMap(_ sender: UIBarButtonItem)
    {
    NotificationCenter.default.post(name: .mapRequested, object: nil)
    }

    ...
    }

    Mais, c'est pourquoi que l'utilisateur ne puisse pas changer le tab soi-même ?

  • Luc-ALuc-A Membre
    novembre 2017 modifié #29

    Grâce à  vous, j'ai réussi !!


     


    Dans l'AppDelegate :



    var map: UIViewController?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    map = storyboard.instantiateViewController(withIdentifier: "MapViewController") // as! MapViewController

    return true
    }

    Pour afficher la carte :



    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    ...
    @IBAction func afficherCarte() {
    let view = appDelegate.map! as! MapViewController
    view.annotation = annotation
    show(view, sender: nil)
    }

    Pour remettre les variables à  0, afin de centrer la carte correctement :



    private func updatePosition() {
    thisAnnotation = nil
    lat = nil
    lng = nil
    }

    Et voilà  ! Il n'y a plus de problème de mémoire.


     


    Je vous remercie pour votre aide !


Connectez-vous ou Inscrivez-vous pour répondre.