2017-07-20 1 views
1

J'utilise Firebase comme structure de données. J'utilise le gestionnaire d'achèvement dans refreshControl de mon UITableView, afin d'arrêter l'actualisation lorsque j'ai fini de charger toutes les données de Firebase.Le gestionnaire d'exécution dans refreshControl a EXC_BAD_ACCESS erreur

override func viewDidLoad() { 
    super.viewDidLoad() 
    self.refreshControl = UIRefreshControl() 
    self.refreshControl!.addTarget(self, action: #selector(refreshData),for: .valueChanged) 
    self.refreshControl!.attributedTitle = NSAttributedString(string: "Update the data") 
    refreshData{ _ in 
     self.refreshControl!.endRefreshing() 
    } 
} 

Et voici ma méthode RefreshData

func refreshData(completionHandler:@escaping (Bool)->()) { 
    //Remove old data 
    self.items.removeAll() 
    //Renew all data 
    var ref: DatabaseReference! 
    ref = Database.database().reference(withPath: "tasks") 
    //Loading local drafts 
    var drafts : [Task]! 
    if let local_drafts = NSKeyedUnarchiver.unarchiveObject(withFile: Task.ArchiveURL.path) as? [Task] { 
     drafts = local_drafts 
    } 
    else{ 
     drafts = [] 
    } 
    //Reloading the database 
    ref.observe(.value, with: { snapshot in 
     var newItems: [Task] = [] 
     self.num_of_tasks = Int(snapshot.childrenCount) 
     for item in snapshot.children { 
      //let local = item as! DataSnapshot 
      //let snapshotValue = local.value as! [String: AnyObject] 
      //print(snapshotValue["main_content"] as! String!) 
      let taskItem = Task(snapshot: item as! DataSnapshot) 
      newItems.append(taskItem!) 
     } 
     let merged = drafts + newItems 
     self.items = merged 
     completionHandler(true) //THIS LINE HAS ERR_BAD_ACCESS 
    }) 
} 

Je pense que le problème pourrait être les deux RefreshData à viewDidLoad. Mais je ne sais pas comment le réparer. Comment pourrais-je ajouter refreshData avec le gestionnaire en tant que sélecteur?

+1

Savez-vous quand vous êtes sur le fil principal (UI)? Chaque fois que vous entrez une fermeture, assurez-vous que vous êtes dans le thread que vous devez être - pour manipuler un contrôle de l'interface utilisateur, vous devez être sur le thread UI et je suppose que vous n'avez pas pris la peine d'arranger ça. – BaseZen

+0

@BaseZen Désolé, je ne comprends pas très bien votre sens. Je commente le refresherControl dans completionHandler et ajoute une instruction d'impression, j'ai toujours cette erreur. –

+1

Si vous ne connaissez pas les contextes de threads et la règle cardinale de manipulation de l'interface utilisateur: qu'il doit être sur le thread principal de l'interface utilisateur - c'est le problème. Voir si la lecture d'arrière-plan sur ces sujets dans iOS aide. – BaseZen

Répondre

1

Ce n'est pas un problème de thread. Je résous en enveloppant l'appel de fonction dans une autre fonction, car dans cette ligne

self.refreshControl!.addTarget(self, action: #selector(refreshData),for: .valueChanged) 

J'ai essayé d'utiliser RefreshData comme un sélecteur, mais en fait, sélecteur n'a pas de gestionnaire d'achèvement par lui-même, de sorte que causé la mémoire erreur lorsque l'utilisateur a essayé de renouveler en faisant glisser la scène vers le bas. Donc, en enveloppant l'appel de fonction dans une autre fonction

func refresh(){ 
     refreshData{ [weak self] _ in 
      if let _ = self { 
       self?.refreshControl!.endRefreshing() 
      } 
     } 
    } 

et utilisez cette fonction dans le sélecteur, il remettra le gestionnaire droit d'achèvement, et résoudre ainsi le problème.