34 votes

Xcode UIView.init(frame :) doit être utilisé uniquement à partir du thread principal.

J'essaie de rendre certaines vues dans un fil de fond pour ne pas affecter le fil principal. Ce n'était jamais un problème avant Xcode 9.

DispatchQueue.global(qos: .background).async {
    let customView = UIView(frame: .zero)
    DispatchQueue.main.async {
        self.view.addSubview(customView)
    }
}

UIView.init(frame :) doit être utilisé uniquement à partir du thread principal.

Cette erreur se produit dans la deuxième ligne.

Mise à jour

La pomme UIView La documentation dit en fait dans le Considérations sur le threading section :

Les manipulations de l'interface utilisateur de votre application doivent avoir lieu sur le thread principal. Ainsi, vous devez toujours appeler les méthodes de la classe UIView à partir du code s'exécutant dans le thread principal de votre application. La seule fois où cela n'est pas strictement nécessaire est lors de la création de l'objet de vue lui-même, mais toutes les autres manipulations doivent avoir lieu sur le thread principal.

0 votes

J'étais au courant de cette nouvelle règle, mais je me demande quelle part du travail vous pouvez encore décharger sur un fil de fond...

31voto

Puneet Points 2782

Xcode 9 a un nouveau runtime Vérificateur de fil principal qui détecte les appels à UIKit depuis un thread d'arrière-plan et génère des avertissements.

Je sais que son but est de générer des avertissements et non de faire planter l'application, mais vous pouvez essayer de désactiver Main Thread Checker pour votre cible de test.

enter image description here

J'ai essayé ce code dans un projet d'exemple, le débogueur s'est arrêté au niveau du problème (comme il est censé le faire), mais l'application ne s'est pas plantée.

override func viewDidLoad() {
    super.viewDidLoad()

    DispatchQueue.global().async {
        let v = UIView(frame: .zero)
    }
}

1 votes

C'est tout pour le moment. Merci !

0 votes

Dans mon cas, j'appelais une méthode à partir d'une requête URLSession.

27voto

Aditya A.Rajan Points 68

Entrée du fil principal

Vous pouvez entrer dans le fil principal comme suit

DispatchQueue.main.async { 
    // UIView usage
}

4 votes

De la revue : Bienvenue sur Stack Overflow ! S'il vous plaît, ne répondez pas seulement avec le code source. Essayez de fournir une bonne description du fonctionnement de votre solution. Voir : Comment rédiger une bonne réponse ? . Merci

23voto

Erhan Demirci Points 1219

Vous pouvez utiliser cette fonction

func downloadImage(urlstr: String, imageView: UIImageView) {
    let url = URL(string: urlstr)!
    let task = URLSession.shared.dataTask(with: url) { data, _, _ in
        guard let data = data else { return }
        DispatchQueue.main.async { // Make sure you're on the main thread here
            imageview.image = UIImage(data: data)
        }
    }
    task.resume()
}

Comment utiliser cette fonction ?

downloadImage(urlstr: "imageUrl", imageView: self.myImageView)

0voto

Gerard Grundy Points 546

Pour Objective C :

 dispatch_async(dispatch_get_main_queue(), ^{

        // UIView usage
        self.view.userInteractionEnabled = YES;
    });

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X