Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
iOS - Visibilità di un attributo NSMutableArray in più metodi della classe
Forum - iOS - Visibilità di un attributo NSMutableArray in più metodi della classe

Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 14:57
Martedì, 08/05/2012
Ciao a tutti, sono nuovo nella programmazione di dispositivi Apple e sto programmando un gioco per iPad come progetto scolastico con le librerie Cocos2d.

Ultimamente purtroppo mi sono bloccato perché l'applicazione va in crash quando cerco di accedere ad un array di tipo NSMutableArray (inizializzato nel metodo init()) in un altro metodo.

L'array dovrebbe contenere oggetti di tipo TeddyBear (classe creata da me).

Codice sorgente - presumibilmente iOS

  1. Codice sorgente - presumibilmente iOS

  2.  
  3. // TeddyBear.h
  4. #import <Foundation/Foundation.h>
  5. #import "cocos2d.h"
  6.  
  7. @interface TeddyBear : NSObject
  8. {
  9.     int life;
  10.    
  11.     CCSprite *_teddyBearSprite;
  12.     CCAction *_walkAction;
  13.     CCAction *_moveAction;
  14.     CCAnimation *_walkAnim;
  15. }
  16.  
  17. @property (nonatomic, retain) CCSprite *teddyBearSprite;
  18. @property (nonatomic, retain) CCAction *walkAction;
  19. @property (nonatomic, retain) CCAction *moveAction;
  20. @property (nonatomic, retain) CCAnimation *walkAnim;
  21.  
  22. - (void) initTeddyBear: (int) l withAnimFrames:(NSMutableArray*) animFrames withSpriteFrameName:(NSString*) spriteFrameName withDelay:(float) d;
  23.  
  24. @end
  25.  
  26.  
  27.  
  28. // TeddyBear.m
  29. #import "TeddyBear.h"
  30.  
  31. @implementation TeddyBear
  32.  
  33. @synthesize teddyBearSprite = _teddyBearSprite;
  34. @synthesize walkAction = _walkAction;
  35. @synthesize moveAction = _moveAction;
  36. @synthesize walkAnim = _walkAnim;
  37.  
  38. - (void) initTeddyBear:(int) l withAnimFrames:(NSMutableArray*) animFrames withSpriteFrameName:(NSString*) spriteFrameName withDelay:(float) d
  39. {
  40.     CGSize winSize = [CCDirector sharedDirector].winSize;
  41.     int rndY;
  42.    
  43.     rndY = arc4random() % ((int) winSize.height - 200) + 110;
  44.     NSLog(@"winSize.height = %f\n", winSize.height);
  45.    
  46.     life = l;
  47.    
  48.     _teddyBearSprite = [CCSprite spriteWithSpriteFrameName:spriteFrameName];
  49.    
  50.     _teddyBearSprite.position = ccp(arc4random() % (int) winSize.width, rndY);
  51.    
  52.     _walkAnim = [CCAnimation animationWithFrames:animFrames delay:d];
  53.     self.walkAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:_walkAnim restoreOriginalFrame:NO]];
  54.     [_teddyBearSprite runAction:_walkAction];
  55. }
  56.  
  57. @end
  58.  
  59.  
  60.  
  61. // HelloWorldLayer.h
  62. #import "cocos2d.h"
  63.  
  64. // HelloWorldLayer.h
  65. @interface HelloWorldLayer : CCLayer
  66. {
  67.     /*CCSprite *_teddyBearSprite;
  68.     CCAction *_walkAction;
  69.     CCAction *_moveAction;
  70.    
  71.     CCArray *_teddyBears;
  72.     int _nextTeddyBear;
  73.     double _nextTeddyBearSpawn;*/
  74.    
  75.     NSMutableArray *_teddyBears;
  76. }
  77.  
  78. //@property (nonatomic, retain) CCSprite *teddyBearSprite;
  79. //@property (nonatomic, retain) CCAction *walkAction;
  80. //@property (nonatomic, retain) CCAction *moveAction;
  81. //@property (nonatomic, assign) NSMutableArray *teddyBears;
  82.  
  83. // returns a CCScene that contains the HelloWorldLayer as the only child
  84. +(CCScene *) scene;
  85.  
  86. @end
  87.  
  88.  
  89.  
  90. // HelloWorldLayer.m
  91. #import "HelloWorldLayer.h"
  92. #import "TeddyBear.h"
  93.  
  94. #define kNumTeddyBears 15
  95.  
  96. […]
  97.  
  98. - (id) init
  99. {      
  100.     if((self = [super init]))
  101.     {
  102.         self.isTouchEnabled = YES;
  103.        
  104.         /* Inizio animazione teddyBear. */
  105.         [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"AnimTeddyBear.plist"];
  106.        
  107.         CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:@"AnimTeddyBear.png"];
  108.         [self addChild:spriteSheet];
  109.        
  110.         NSMutableArray *walkAnimFrames = [NSMutableArray array];
  111.         for(int i = 1; i <= 4; ++i)
  112.         {
  113.             [walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"teddybear%d.png", i]]];
  114.  
  115.         _teddyBears = [NSMutableArray array];
  116.        
  117.         TeddyBear *tmpTeddyBear = [TeddyBear new];
  118.        
  119.         //[tmpTeddyBear initTeddyBear:1 withAnimFrames:walkAnimFrames withSpriteFrameName:@"teddybear1.png" withDelay:0.09f];
  120.        
  121.         for(int i = 0; i < kNumTeddyBears; i++)
  122.         {
  123.             [tmpTeddyBear initTeddyBear:1 withAnimFrames:walkAnimFrames withSpriteFrameName:@"teddybear1.png" withDelay:0.09f];
  124.             [spriteSheet addChild:[tmpTeddyBear teddyBearSprite]];
  125.             [_teddyBears addObject:tmpTeddyBear];
  126.         }
  127.        
  128.         NSLog(@"Grandezza _teddyBears: %d in init()\n", [_teddyBears count]);
  129.         int i = 0;
  130.         for(TeddyBear *tb in _teddyBears)
  131.         {
  132.             NSLog(@"i = %d\n", i);
  133.         }
  134.     }
  135.  
  136.     return self;
  137. }
  138.  
  139. […]
  140.  
  141. -(void) ccTouchEnded:(UITouch *) touch withEvent:(UIEvent *) event {    
  142.     CGPoint location = [touch locationInView:[touch view]];
  143.     location = [[CCDirector sharedDirector] convertToGL:location];
  144.     NSLog(@"Grandezza _teddyBears: %d in ccTouchEnded\n", [_teddyBears count]);
  145. }
  146.  
  147. […]




L'applicazione va in crash nell'ultima riga del metodo -(void) ccTouchEnded… durante la stampa quando tenta di accedere a [_teddyBears count], è come se l'array non esistesse più dopo essere uscito dal metodo init().

PM Quote
Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 18:04
Martedì, 08/05/2012
Come non detto, ho risolto usando un CCArray al posto di un NSMutableArray :D

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 19:20
Martedì, 08/05/2012
Ti consiglio di studiare un po' piu' a fondo il meccanismo di gestione della memoria dell'Objective-C. E' un po' contorto, ma e' fondamentale capire come funziona.

Quando inizializzi il tuo array in init:

Codice sorgente - presumibilmente Plain Text

  1. _teddyBears = [NSMutableArray array];



Il reference count per l'oggetto e' a uno. Quando esci da init, il reference count viene decrementato (quindi 1-1 = 0), l'oggetto viene rilasciato e il tuo puntatore fa ora riferimento ad uno spazio di memoria deallocato.

Per risolvere:

Codice sorgente - presumibilmente Plain Text

  1. _teddyBears = [[NSMutableArray array] retain];



Retain aumentera' il reference count a 2. Quando init esce, il reference count sara' ad 1 (2 - 1 = 1). Poi quando hai finito di usare l'array (nel distruttore della scena?) ricordati di chiamare:

Codice sorgente - presumibilmente Plain Text

  1. [_teddyBears release];



Che decrementera' il reference count di 1, raggiungendo 0 e quindi deallocando lo spazio.


Il mio blog: https://piero.dev
PM Quote
Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 19:04
Giovedì, 10/05/2012
Grazie, come al solito le tue risposte sono brillanti :D
Sì in effetti non l'ho studiata per niente la gestione della memoria, vedrò di rimediare ;)

PM Quote
Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 15:54
Sabato, 12/05/2012
Ok ho capito come funzionano retain e release ma se io avessi una variabile primitiva come dovrei fare? Ho per esempio un float che viene inizializzato nel metodo init(), poi vorrei modificarlo in update() ma non viene modificato e rimane sempre dello stesso valore, ho provato in vari modi e ho cercato su internet ma non ho trovato niente :(

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 17:35
Sabato, 12/05/2012
?

I primitivi non hanno bisogno di essere allocati/deallocati. Release, retain & co sono solo per gli oggetti.


Il mio blog: https://piero.dev
PM Quote
Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 15:16
Domenica, 13/05/2012
Sì lo so infatti ho sempre fatto così anche negli altri linguaggi però adesso ho una variabile float (float time) dichiarata nell'interfaccia HelloWorldLayer, in init() faccio time = CFAbsoluteTimeGetCurrent(); e successivamente in update() che viene chiamata ogni non so quanti ms rifaccio time = CFAbsoluteTimeGetCurrent(); ma il valore di time non cambia mai e rimane sempre lo stesso di quando l'ho inizializzata in init(). In poche parole è come se in update non venisse assegnato nessun valore a time pur dopo aver fatto l'assegnazione, è strana come cosa non riesco a spiegarmela...

PM Quote
Avatar
_mikele_ (Member)
Rookie


Messaggi: 40
Iscritto: 06/12/2010

Segnala al moderatore
Postato alle 12:25
Martedì, 15/05/2012
Risolto, ho usato CACurrentMediaTime() al posto di CFAbsoluteTimeGetCurrent() :)

PM Quote