2012-06-04 2 views
1

J'essaie de comprendre comment les choses fonctionnent en ce qui concerne la programmation simultanée et l'appel de setNeedsDisplay. J'ai essentiellement trois objets.Comprendre setNeedsDisplay/drawRect avec des blocs

Main View - container with different UIView objects, the main one being a UIScrollView 
Small Map View - a small UIView that draws a miniature version of one of the other UIView items on screem 
Processor - a delegate of the Main View that calculates what's on screen and calls the Main View back with what's in view. 

donc d'un simple cas d'utilisation de ce qui se passe est que l'utilisateur touche le ScrollView et le processeur met à jour ce qui est en vue de la ScrollView (comme coordonnées calcul, point central, etc.) Il fait cela bloque à l'aide et fait de manière asynchrone. Cela envoie ensuite une notification à l'objet MainView.

Lorsque le MainView reçoit la notification, il appelle simplement

[smallMap setNeedsDisplay]; // example 1 

Je mis quelques journaux autour de cet appel, et je ne vois qu'il est appelé tout de suite. Cependant, le drawRect: de cette fonction n'est pas appelé tout de suite. Il est appelé après 2 secondes environ.

Je me souviens d'avoir lu que setNeedsDisplay marque juste la vue pour que le redraw se produise sur le prochain événement de la boucle d'exécution.

Mais si j'ajoute ce code à la place:

// example 2 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [smallMap setNeedsDisplay];   
    }); 

Mon point de vue se redessiner tout de suite. Je suppose que je suis confus quant à la raison pour laquelle je dois demander à la boucle d'événement principal d'appeler setNeedsDisplay pour redessiner quelque chose immédiatement. Comme dans l'exemple 1, en appelant setNeedsDisplay, est-ce que c'est fait en arrière-plan ou quelque chose et c'est pourquoi il n'est pas redessiné tout de suite? J'essaie de comprendre la différence dans ce qui se passe dans les coulisses, donc je sais ce qu'il faut chercher dans le futur. Comme dois-je avoir tous mes appels qui doivent être immédiatement redessinés dans quelque chose de semblable à l'exemple 2 bloc? Ou est-ce parce que je traite mes données de manière asynchrone que je dois alors demander la file d'attente principale? Merci!

Répondre

2

Je pense 1 2 choses:

Votre code qui est en cours d'exécution sur un thread séparé appelle vos méthodes de MainView du thread séparé au lieu d'utiliser performSelectorOnMainThread ou un appel GCD qui invoque le code sur le thread principal . Ainsi, votre appel à setNeedsDisplay se déroule réellement sur un thread d'arrière-plan, ce qui est un non-non, comme l'a dit l'autre affiche. La seconde possibilité est que votre code MainView s'exécute sur le thread principal, mais il est occupé à effectuer un traitement fastidieux ou à attendre la fin d'un appel synchrone vers un autre thread et ne gère pas la boucle d'événements.

Vous pouvez exclure la première possibilité en définissant un point d'arrêt sur votre appel à setNeedsDisplay et en regardant la trace d'appel dans le débogueur pour voir à partir de quel thread il s'exécute. Comprendre la deuxième possibilité demandera un peu plus de travail. Vous pourriez avoir besoin de plonger dans des instruments.

2

setNeedsDisplay est un appel API UIKIT qui doit être appelé depuis le thread principal de l'application, également appelé thread UI. C'est pourquoi l'appeler dans un thread d'arrière-plan n'a aucun effet immédiat et le programmer dans la file d'attente principale a des effets immédiats.

Voir cette question connexe https://stackoverflow.com/a/6988115/172690 pour une réponse plus détaillée.

+0

Cela est vrai, mais ne s'applique pas à cette question.Il utilise dispatch_async mais distribue dans la file d'attente principale, ce qui devrait fonctionner correctement. – Jiri

+1

Euh, vraiment? Ce que je lis, c'est que son code (voir l'exemple 1) ne fonctionne pas à moins qu'il ne le distribue sur le thread principal (exemple 2). Vous déclarez utiliser dispatch_async avec la file d'attente principale, ce que je suis d'accord. La question est de savoir pourquoi, et je suppose que je n'ai pas répondu à cette question si je confondais aussi les autres. Pardon. –

+0

La façon dont j'ai compris la question était que l'exemple 1 a été appelé sur la file d'attente principale et l'exemple 2 sur une autre file d'attente. Dans les deux cas, l'appel UIKit s'exécuterait dans la file d'attente principale, ce qui serait OK. J'ai peut-être mal compris, désolé. – Jiri