2010-09-28 8 views
1

Cette question m'a vraiment déconcerté ...accident tandis que dans CALayer -hitTest:

J'ai un projet iPad que j'utilise UIPanGestureRecognizer et je suis en utilisant l'appel de méthode suivante dans mon handlePanGesture:

- (AIEnemyUnit *) hitTestForEnemyUnit:(CGPoint)where { 
    CALayer * layer = [self hitTest:where]; 

    while (layer) { 
     if ([layer isKindOfClass:[AIEnemyUnit class]]) { 
      return (AIEnemyUnit *)layer; 
     } else { 
      layer = layer.superlayer; 
     } 
    } 

    return nil; 
} 

Une fois que je "trouve" un calque AIEnemyUnit, je continue avec le glisser et tout fonctionne bien. Sauf au sujet autour du 6 au 10 « glisser » Je reçois un accident avec le débogueur au plus profond de la seule CALayer -hitTest:

modifying layer that is being finalized - 0x124530 
*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: 
'*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530' 

Répondre

1

D'après les symptômes, il semble que vous avez un sur la libération d'un CALayer.

Deux domaines que vous devez vérifier:

1) Êtes-vous sauver »cette CALayer dans une variable sans la retenir? Si vous frappez des pools autorelease (y compris celui fourni sur le thread principal), ces couches pourraient être libérées involontairement. Comme indiqué dans les commentaires, puisque ceux-ci ne sont pas autoeleased, cela peut arriver sans frapper un pool. Cela peut arriver à chaque fois que le CALayer est publié alors que vous détenez une référence.

2) Vous appelez explicitement la version de ce calque plus tard. Étant donné que cette couche est donnée telle quelle (les deux hitTest: et superlayer renvoient des objets sans compte supplémentaire), vous ne possédez pas de propriété et vous ne devez donc pas la libérer.

Un autre outil utile pour le débogage utilise NSZombies et d'autres techniques liées. NSZombies permet essentiellement à votre application de se bloquer au moment où vous accédez à un objet libéré, ce qui, espérons-le, vous donnera une trace de pile plus significative.

+0

Bonne réponse. Une chose: les calques retournés par 'hitTest:' et 'superlayer' ne sont pas auto-libérés, mais ils ne sont pas conservés non plus. Cela peut potentiellement provoquer un blocage: CALayer * sous-couche = [[sous-couches de couche] objectAtIndex: 0]; [sous-couche removeFromSuperlayer]; [sous-couche superlayer]; ' – rpetrich

+0

Merci, je n'étais pas tout à fait sûr, mais je savais qu'ils n'étaient pas la propriété de l'appelant. Je l'ai réparé. – bobDevil

+0

Merci pour la correction! J'avais changé de '@synthesize dragItem;' à un setter manuel et oublié de mettre 'dragItem = [newDragItem retain];'. J'avais vu dans d'autres posts que le message "modifier la couche en cours de finalisation" était lié à des problèmes de nombre de rétention, mais mes messages d'erreur étaient complètement différents que je n'étais pas sûr si c'était la réponse. Mais à cause des autres posts, j'ai soigneusement passé en revue mon code pour voir combien de fois j'appelais -release et -removeFromSuperlayer. J'étais tellement concentré sur l'aspect de la sortie que je ne pensais pas le retenir, alors merci –

0

Je pense qu'il y a un peu de 'désinformation' dans la documentation de hitTest en fait. J'ai moi-même rencontré un problème similaire en mettant 4 instances d'une vue sous-classée sur la fenêtre, chacune avec quatre sous-couches. Chacune des sous-classes de vue 4 avait une méthode touchesBegan: withEvent et une méthode touchEnded: withEvent définie. J'ai trouvé que si mon toucher atterrissait ou se terminait dans la vue la plus à gauche, mon hitTest renvoyait une sous-couche valide. Toutefois, hitTests dans l'une des trois autres affichages renvoyé nil pour la sous-couche. Comme vous, j'étais totalement perplexe jusqu'à ce que je décide de remplacer le point de contact dans le système de coordonnées de la vue par celui du système de coordonnées de la fenêtre et que tout a fonctionné. Je reproduis la documentation de la méthode hitTest:

hitTest: Renvoie le descendant le plus éloigné du récepteur dans la hiérarchie de couches (y compris elle-même) qui contient un point spécifié.

- (CALayer *)hitTest:(CGPoint)thePoint 

Paramètres aubut Un point dans le système de coordonnées de la surcouche du récepteur. Valeur de retour Couche contenant le point, ou zéro si le point se trouve en dehors du rectangle des limites du destinataire.

Disponibilité Disponible avec Mac OS X 10.5 et versions ultérieures. Déclarée dans CALayer.h

Je dirais, d'après mes observations, que l'explication de 'thePoint' est fausse. Je pense qu'il devrait lire 'Un point dans le système de coordonnées de la fenêtre contenant le récepteur.«Je pense que la seule raison pour laquelle la vue en haut à gauche a donné des hitTests valides était parce que les coordonnées du toucher - à cet endroit - sont les mêmes que les coordonnées du toucher dans la fenêtre. Je ne sais pas si cela vous aide, mais cela m'a aidé à faire fonctionner ma logique. V.V.