Moi, aloitteleva iPhone-ohjelmoinnin harrastaja kyselee.
Minulla on harjoitusprojektina peli/lelusovellus, jossa näyttöä koskettamalla luodaan ruutuun planeettoja, jotka sitten liikkuvat painovoimalakien mukaisesti. Koodini ei ehkä ole ihan validia, mutta olen saanut touches-metodeilla luotua ja siirreltyä uusia planeettoja, jotka olen tallentanut NSDictionaryyn, ja piirrettyä niitä ruutuun drawRect-metodilla. Timer eventinkin olen saanut käyntiin planeettojen liikkeiden laskemista ym. varten, mutta koodini bugittaa kun yritän kutsua dictionaryyn tallennetun planeettainstanssin metodeja Timer-metodistani käsin.
Tähän solarSystem-nimiseen NSMutableDictionaryn instanssiin tallennan touchesBegan-metodissa luodut planeetat:
Koodi: Valitse kaikki
@interface SolarSystemView : UIView {
...
NSMutableDictionary *solarSystem;
}
Tässä, SolarSystemViewissä sijaitsevassa touchesMoved-metodissa haetaan solarSystem -dictionarystä oikea planeetta, siirretään sitä kosketuksen uuteen sijaintiin ja kasvatetaan samalla sen kokoa. Täällä aPlanet-instanssin metodikutsut toimivat ihan normaalisti:
Koodi: Valitse kaikki
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInView:self];
NSString *addressToTouchThatMovedAPlanet = [[NSString alloc] initWithFormat:@"%u", touch];
Planet *aPlanet = [solarSystem objectForKey:addressToTouchThatMovedAPlanet];
[aPlanet movePlanetToLocation:touchLocation]; //metodi toimii normaalisti
[aPlanet growPlanetUnderConstruction]; //metodi toimii normaalisti
...
[self setNeedsDisplay];
}
}
Ylläoleva koodi kasvattaa planeetan kokoa kuitenkin vain silloin kun kosketuksen sijainti muutttuu. Tarkoitus olisi, että planeetan koko kasvaisi tasaisesti niin kauan kuin kosketus on voimassa, joten growPlanet… metodia pitäisi päästä kutsumaan ajastinmetodista käsin.
View Controllerissani sijaitsevan Timer metodin koodi:
Koodi: Valitse kaikki
// Miksi aPlanetin metodit ei toimi????
-(void) updateSolarSystem: (NSTimer*)theTimer {
NSLog(@"Jottain!");
int createdPlanets = 0;
for (Planet *aPlanet in [solarSystemView solarSystem]){
createdPlanets++;
[aPlanet growPlanetUnderConstruction]; //tässä app katkeaa, aPlanet ei tunnistakaan growPlanet… metodia täällä, miksi?
}
NSLog([NSString stringWithFormat:@"%i", createdPlanets]);
}
Tuossa ylläolevassa koodissa tuo growPlanet... kuten aPlanetin kaikki muutkin metodikutsut katkeavat "unrecognized selector"-virheeseen. Mistähän tämä voisi johtua? Login mukaan luuppi toimii, ja jos softan kaatavia aPlanetin metodeita ei kutsuta, myös luotujen planeettojen määrä näkyy logissa ihan oikein.
Kohteleeko tuo "for (Class *instance in [dictionary]" instanssia jotenkin eri tavalla kuin tuo "Class *instance = [dictionary objectForKey: key]"? Vai onko kenties kyse jostain scope-ongelmasta? Cocoa-treenit on tosiaan ihan alkumetreillä, joten en oikein hahmota, missä voisi olla vika.
Tässä vielä logi, jossa näkyy kaatumishetken virheilmoitus:
…
2011-05-16 00:09:45.465 SolarSystem[778:207] 0
2011-05-16 00:09:45.714 SolarSystem[778:207] Jottain!
2011-05-16 00:09:45.715 SolarSystem[778:207] 0
2011-05-16 00:09:45.964 SolarSystem[778:207] Jottain!
2011-05-16 00:09:45.965 SolarSystem[778:207] -[NSCFString growPlanetUnderConstruction]: unrecognized selector sent to instance 0x4e12db0
2011-05-16 00:09:45.966 SolarSystem[778:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString growPlanetUnderConstruction]: unrecognized selector sent to instance 0x4e12db0'
*** Call stack at first throw:
(
0 CoreFoundation 0x00dadbe9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f025c2 objc_exception_throw + 47
2 CoreFoundation 0x00daf6fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d1f366 ___forwarding___ + 966
4 CoreFoundation 0x00d1ef22 _CF_forwarding_prep_0 + 50
5 SolarSystem 0x00004554 -[SolarSystemViewController updateSolarSystem:] + 302
6 Foundation 0x0004c7a5 __NSFireTimer + 125
7 CoreFoundation 0x00d8efe3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
8 CoreFoundation 0x00d90594 __CFRunLoopDoTimer + 1220
9 CoreFoundation 0x00ceccc9 __CFRunLoopRun + 1817
10 CoreFoundation 0x00cec240 CFRunLoopRunSpecific + 208
11 CoreFoundation 0x00cec161 CFRunLoopRunInMode + 97
12 GraphicsServices 0x016e2268 GSEventRunModal + 217
13 GraphicsServices 0x016e232d GSEventRun + 115
14 UIKit 0x002c542e UIApplicationMain + 1160
15 SolarSystem 0x00001d1c main + 102
16 SolarSystem 0x00001cad start + 53
17 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
Program received signal: “SIGABRT”.
(gdb)