utilisation de l'accéléromètre : des questions

macounettemacounette Membre
19:33 modifié dans API UIKit #1
Bonjour (enfin bonsoir plutôt)

Je souhaite utiliser l'accéléromètre sur mes balles en mouvement. J'ai une vue BallView qui contient un tableau d'objet Ball.

Dans ma classe NSObject ball :

<br />CGPoint acceleratedGravity;<br />UIAccelerometer sharedAccelerometer<br />


au moment d'initialiser la balle
<br />[[UIAccelerometer sharedAccelerometer] setDelegate:self];<br />acceleratedGravity = CGPointMake(0.0, gravity);<br />


le méthode :
<br />- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {<br />&nbsp; &nbsp; acceleratedGravity.x = acceleration.x * gravity;<br />&nbsp; &nbsp; acceleratedGravity.y = -acceleration.y * gravity;<br />}<br />


L'effet de l'accéléromètre n'est pris en compte que sur ma 1ère balle. Les autres ne sont pas affectées. Est-ce que l'accéléromètre doit être définit dans ma ballView ? Pourquoi je ne peux pas l'utiliser comme ça ?

Merci !

Réponses

  • AliGatorAliGator Membre, Modérateur
    19:33 modifié #2
    UIAccelerometer est un singleton. Tu le vois d'ailleurs en l'utilisant : tu n'alloues pas un nouvel objet UIAccelerometer avec allocinit, tu demandes bien le "sharedAccelerometer", ce qui veux bien dire que cet objet représentant l'accéléromètre est un objet "partagé", une seule instance pour tout ton programme. C'est comme ça qu'il fonctionne.

    Du coup quand tu fais "setDelegate:self" sur ce sharedAccelerometer, cela modifie le delegate... du sharedAccelerometer, l'instance unique donc !
    Du coup pour chaque balle que tu instancies, tu ne crées pas un nouvel accéléromètre (ça c'est pas possible de toute façon, c'est un singleton cet UIAccelerometer), mais tu modifies le delegate de l'unique accéléromètre de ton application... forcément pour la première balle tu mets cette balle comme delegate, mais pour la 2e tu remplaces le delegate de ton accéléromètre par cette 2e balle... etc.

    Ce qu'il te faut donc c'est ne définir qu'un seul delegate de l'accéléromètre, quitte à  ce que ce dernier renvoie le message à  d'autres objets, par exemple via des notifications pour informer lesdits objets (tes balles en l'occurrence) que l'accéléromètre a bougé, ou via un tableau de ces objets que ton delegate d'accéléromètre connaà®trait et il pourrait appeler une méthode sur chacun des objets... Par exemple si c'est ta vue qui te sert de "plateau" (ta superview parente de tes balles) qui est delegate de l'accéléromètre, elle connaà®t a sans doute quelque part un tableau contenant toutes ces balles justement, j'imagine ? Et dans ce cas tu peux appeler une méthode maison (genre "changeGravity:" ou tu l'appelles comme tu veux, et tu lui passes ton objet UIAcceleration) sur chaque balle.
  • macounettemacounette Membre
    mars 2009 modifié #3
    Ok merci pour les explications, je comprends mieux, c'est pas évident de trouver de la doc sur internet là -dessus. Par contre pour ce qui est des notifications je n'arrive pas vraiment à  comprendre comment les NSNotification s'utilisent donc j'essaie de faire sans.

    Bon avec 1 balle je n'ai pas de problèmes. Avec 2 balles et 1 vue, no problem aussi.
    Ca coince avec 2 vues...

    Donc je récapitule, j'ai un Controller dans lequel j'ai 2 vues UIView. Dans chaque UIView j'ai un tableau de balles.

    Mon controller :
    <br />- (void)loadView {<br />BallView1 = [[[BallView alloc]&nbsp; initWithFrame:...] autorelease];<br />BallView2 = [[[BallView alloc]&nbsp; initWithFrame:...] autorelease];<br />[self.view addSubview: BallView1];<br />[self.view addSubview: BallView2];<br />...<br />[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(.1)];<br />[[UIAccelerometer sharedAccelerometer] setDelegate:self];<br />}<br /><br />- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {<br />&nbsp; &nbsp;[BallView1 updateViewWithX:acceleration.x Y:acceleration.y];<br />&nbsp; &nbsp;[BallView2 updateViewWithX:acceleration.x Y:-acceleration.y];<br />}<br />
    


    Ma BallView
    <br />- (void)updateViewWithX:(float)x Y:(float)y&nbsp; {<br />	for(int i=0; i&lt;ballNumber; i++) {<br />		Ball* ball = [iconArray objectAtIndex:i];<br />		[ball updateBallWithX X:x Y:y];<br />	}<br />}<br />
    


    Mon NSObject balle
    <br />- (void)setEndPointX:(CGFloat)x Y:(CGFloat)y<br />{<br />	acceleratedGravity.x=x; //acceleratedGravity est un CGPoint<br />	acceleratedGravity.y=y;<br />}<br />
    


    Avec ça je n'obtiens pas grand chose. Aucune de mes balles ne réagit à  l'accéléromètre :(

    J'avance doucement, mais sûrement, et surtout j'aimerais avancer en comprenant. Allez courage !  <3 <br />
  • muqaddarmuqaddar Administrateur
    19:33 modifié #4
    Déterrage de post...

    Je fais mes premiers pas avec l'accéléromètre...

    Dans mon viewDidLoad :
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];
    


    donc je désigne mon instance de classe comme délégué de l'accéléromètre...

    Tout se passe bien dans la methode delegate, il m'affiche mes accélérations avec un NSLog.

    Et hop, dès que je sors de ma vue (bouton retour de navigationController), plantage...
    je sais que ça vient de l'accéléromètre car dès que j'enlève ma ligne :

    [[UIAccelerometer sharedAccelerometer] setDelegate:self];
    


    pas de plantage...

    J'ai un bête Ex_bad_access, donc un problème de mémoire sur ce singleton ???

    J'ai essayé d'ajouter cela à  ma classe :

    - (void)viewDidDisappear {<br />	NSLog(@&quot;disapear&quot;);<br />	[[UIAccelerometer sharedAccelerometer] setDelegate:nil];<br />}<br />
    


    mais il n'est pas appelé. La vue est chargée par un viewController (navigationController).
  • AliGatorAliGator Membre, Modérateur
    mai 2009 modifié #5
    dans 1242841569:

    J'ai un bête Ex_bad_access, donc un problème de mémoire sur ce singleton ???
    Non, pas sur le singleton, sur le delegate.

    Il est évident qu'il faut que tu désattribues ton delegate lorsque ton objet self risque d'être détruit, potentiellement donc en effet quand ta vue va disparaà®tre.
    Car sinon le delegate (ton viewController) est released quand tu le fais disparaà®tre de l'écran... mais le delegate étant en @property "assign" dans le sharedAccelerometer, il n'est pas retenu ailleurs : donc il est détruit alors que tu gardes un pointeur dessus dans ton sharedAccelerometer qui essaye d'envoyer des messages à  cet objet qui n'existe plus... d'où le EXC_BAD_ACCESS, tentative d'accéder à  un emplacement mémoire (pointé par delegate mais) qui n'existe plus.

    dans 1242841569:
    J'ai essayé d'ajouter cela à  ma classe :

    - (void)viewDidDisappear {<br />	NSLog(@&quot;disapear&quot;);<br />	[[UIAccelerometer sharedAccelerometer] setDelegate:nil];<br />}<br />
    

    Mettre le delegate=nil dans le viewDidDisappear est une bonne idée à  la base, donc, en effet, pour ne plus que l'accéléromètre essaye de lui envoyer des messages alors qu'il va être détruit.
    Mais pourquoi ne pas le mettre dans "[tt]- (void)viewDidUnload[/tt]" plutôt, puisque c'est la méthode "mirroir" du [tt]- (void)viewDidLoad[/tt] dans laquelle tu as affecté ton delegate ?

    dans 1242841569:
    mais il n'est pas appelé. La vue est chargée par un viewController (navigationController).

    Ton viewDidDisappear n'est pas appelé tout simplement car tu n'as pas utilisé la bonne signature : il faut utiliser, comme indiqué dans la doc de UIViewController, [tt]- (void)viewDidDisappear:(BOOL)animated[/tt] et donc ne pas omettre le paramètre ;)
  • muqaddarmuqaddar Administrateur
    19:33 modifié #6
    Ali,

    Ta réponse est triplement claire.

    1) J'ai tout pigé.

    2) Pourquoi j'ai omis le paramètre à  viewDidDisappear ? Parce que xCode ne bronche pas quand on l'oublie ! Je devrais avoir un warning car la déclaration n'est pas présente dans le .h, et que donc ce n'est plus une methode delegate.

    3) Je ne savais pas que viewDidUnload existait !

    En tout cas : 
  • AliGatorAliGator Membre, Modérateur
    19:33 modifié #7
    dans 1242847854:

    2) Pourquoi j'ai omis le paramètre à  viewDidDisappear ? Parce que xCode ne bronche pas quand on l'oublie ! Je devrais avoir un warning car la déclaration n'est pas présente dans le .h, et que donc ce n'est plus une methode delegate.
    Non ça c'est normal : c'est si tu essayais d'appeler une méthode, définie dans ton .m mais pas déclarée dans ton .h, là  Xcode te mettrais un warning genre "attention tu essayes d'appeler la méthode machin mais elle est pas déclarée dans le .h donc je suis pas sûr que tu saches y répondre"

    Mais là  tu as déclaré une méthode... que personne n'utilise. Ni toi, ni le runtime Cocoa, puisque lui il appelle awakeFromNib, viewDidLoad, viewDidDisappear:, mais pas viewDidDisappear sans argument.
    Donc personne n'appelle cette méthode, il n'a pas de raison de te mettre de warning à  son propos.

    dans 1242847854:
    3) Je ne savais pas que viewDidUnload existait !
    Moi non plus ;D Mais j'étais pas sûr de l'existance de viewDidDisappear: non plus... En allant regarder dans la doc du coup j'en ai profité pour vérifier si un viewDidUnload n'existait pas tellement ça me semblait logique que ça existe... et bingo ^^ :)
  • muqaddarmuqaddar Administrateur
    19:33 modifié #8
    Bien joué en tout cas ! ;)
Connectez-vous ou Inscrivez-vous pour répondre.