The incoming scene allocates before the current scene can pass data - iphone

I am trying to pass data (score) between two scenes.However, my second scene is allocating before the first scene can pass the data. Not sure why. My code:
MainScreen.m
-(void)gameOver
{
self.view.scene.userData = [[NSMutableDictionary alloc]init];
[self.view.scene.userData setObject:self.score forKey:#"score"];
SVGGameOverScreen *gameOverScreen = [[SVGGameOverScreen alloc]initWithSize:self.size];
gameOverScreen.view.scene.userData = [[NSMutableDictionary alloc]init];
[gameOverScreen.userData setObject:[self.view.scene.userData objectForKey:#"score"] forKey:#"score"];
NSLog(#"Value of score (FIRST SCREEN): %d", self.score.intValue);
NSLog(#"Value of object for score key (FIRST SCREEN) %#", [self.userData objectForKey:#"score"]);
[self.backgroundMusicPlayer stop];
//Transition to new view
SKTransition *transition = [SKTransition pushWithDirection:SKTransitionDirectionUp duration:1.0];
transition.pausesOutgoingScene = YES;
[self.view presentScene:gameOverScreen transition:transition];
}
GameOverScreen.m
in init method
...
self.score = [[NSNumber alloc]init];
self.score = [self.userData objectForKey:#"score"];
NSLog(#"Value of object for score key (SECOND SCREEN) %#", [self.userData objectForKey:#"score"]);
Output is as follows when gameOver is called:
2013-12-18 15:47:48.646 [] Value of object for score key (SECOND SCREEN) (null)
2013-12-18 15:47:48.700 [] Value of score (FIRST SCREEN): 26
2013-12-18 15:47:48.700 [] Value of object for score key (FIRST SCREEN) 26

If you call
[SVGGameOverScreen alloc]initWithSize:self.size];
and don't set the userData inside it, of course it won't be set until after the method returns. Either write a new method which reproduces whatever logic you need to do after userData is set, pass it into the game over screen with a new method like this
initWithSize: (CGSize) size userData: (NSMutableDictionary*) userData
and set it inside, or (probably better) make a custom setter for the property and put the logic there.
Incidentally, why are you creating an NSNumber for score only to set it equal to the value userData's "score" key?

Related

shallow copy and deeply copy in object-c

I have question about "copy" in objective-c, my function in Car.m is like this:
- (id) copyWithZone: (NSZone *) zone
{
Car *carCopy;
carCopy = [[[self class] allocWithZone: zone] init];
carCopy.name = self.name; //not [name copy]
return (carCopy);
} // copyWithZone
int the main.m:
Car *car = [[Car alloc] init];
car.name = #"abc";
Car *copyCar = [car copy];
[copyCar print];
car.name = #"123";
[copyCar print];
for the property name , i think both the car and copyCar point to the same NSString Object so that when I do "car.name = #"123" " , copyCar.name should also be changed. But when i print the copyCar twice as in the code, they both print the name as "abc". I want to know why it is not a shallow copy ?
Two things:
1) they may both start out pointing to the same NSString, but when you do car.name = #"123", you are now making car.name point someplace else. You are changing the pointer, not the object it points to, and changing the pointer in car does not affect the pointer in copyCar. If you (hypothetically) did something like [car.name appendString:#"xxx"], that would change the object. But, you can't, because
2) NSStrings are immutable -- you can't change the NSString object once it's been created
You're not mutating the string for the name property. You're replacing it outright. Since car and copyCar are not, in fact, the same object, assigning to car.name cannot possibly affect copyCar.name.
Both car and copyCar point to the same string initially, but they both have different references to the same string. If you change the reference in one object, it doesn't affect the reference in the other object, so that's how car can point to the new string but not the carCopy.

label not updating in setter

ok so this problem is kinda weird because the NSLog I have right in front of the line of code that should be printing out the text is returning the correct value.
Here's the code:
-(void)setCurrentDate:(UILabel *)currentDate
{
NSInteger onDay = 1; //because if it's today, you are on day one, not zero... no such thing as a day zero
//get the nubmer of days left
if( [[NSUserDefaults standardUserDefaults] objectForKey:#"StartDate"] ){ //if there is something at the userdefaults
onDay = [self daysToDate:[NSDate date]];
}//otherwise, onDay will just be one
self.theCurrentNumberOfDaysSinceStart = onDay;
NSLog(#"On day: %d", onDay); //this is returning the correct values....
//print it out on the label
[currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];//echoes out the current day number
}
So when the app first launches, everything is fine. The label updates and everything. The problem arises when I hit a button that basically grabs a new date. In the process, it runs this:
//need to reload the "on day" label now
[self setCurrentDate:self.currentDate];
//and the "days left" label
[self setDaysLeft:self.daysLeft];
Again, I'm thinking this should all be correct because the NSLog is returning the correct stuff. I'm thinking that the problem is with the last line in the first block of code I showed... the line with the setText.
thanks for all your help!
cheers,
Matt
If you used a nib
When the nib loads and establishes all of it connections it... (From the Resource Programming guide)
looks for a method of the form set OutletName: and calls it if such a method is present
Therefore the nib will load and call setCurrentDate: passing in the unarchived UILabel as the parameter
In your method you configure the UILabel using the local reference passed into the method
[currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];
You at no point actually store a reference to this UILabel in an ivar, so technically you have leaked the label and as you have not set the ivar currentDate it will be initialised to nil. This is the danger of overriding a setter with an incorrect implementation.
At some point in your method you should be setting your ivar to the passed in variable. A normal setter would look like this
- (void)setCurrentDate:(UILabel *)currentDate;
{
if (_currentDate != currentDate) {
[_currentDate release];
_currentDate = [currentDate retain];
}
}
But
In your example I would not worry about this at all I would instead change this
//need to reload the "on day" label now
[self setCurrentDate:self.currentDate];
to something like
[self updateCurrentDate];
The implementation would look something like:
- (void)updateCurrentDate;
{
NSInteger onDay = 1;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"StartDate"]) {
onDay = [self daysToDate:[NSDate date]];
}
self.theCurrentNumberOfDaysSinceStart = onDay;
[self.currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];
}

Creating a MKPolygon from user-placed annotations in map

I want the user to be able to create polygons after placing some (unknown number) MKpointAnnotations in the map.I have put a gesture recognizer that gets activated once the user taps a button, and so annotations are placed.But how to use these as corners for a MKPolygon?
Below the code for saving the corners of the polygon.This after some mods I did to it.Now the app crashes and the crash reporter says index out of range.The corners are MKPointAnnotation-s created via a GestureRecognizer.
-(IBAction)addCorner:(id)sender
{
NSMutableArray *addCorners = [[NSMutableArray alloc] init];
[addCorners addObject:pointAnnotation];
ptsArray = addCorners;
}
-(IBAction)addPolygonOverlay:(id)sender
{
int cornersNumber = sizeof(ptsArray);
MKMapPoint points[cornersNumber];
for (int i=0; i<cornersNumber; i++) {
points[i] = MKMapPointForCoordinate([[ptsArray objectAtIndex:i] coordinate]);
}
MKPolygon *polygon = [MKPolygon polygonWithPoints:points count:cornersNumber];
[mapview addOverlay:polygon];
}
First problem is the addCorner method. Instead of adding each corner to the ptsArray variable, it creates a new array with just the last corner and sets theptsArray equal to that so it only has the one, last corner.
Change the addCorner method like this:
-(IBAction)addCorner:(id)sender
{
if (ptsArray == nil)
{
self.ptsArray = [NSMutableArray array];
}
[ptsArray addObject:pointAnnotation];
}
Also make sure ptsArray is declared and synthesized properly:
//in the .h file...
#property (nonatomic, retain) NSMutableArray *ptsArray;
//in the .m file...
#synthesize ptsArray;
(By the way, why not add the corner to ptsArray right where the pointAnnotation is created instead of in a separate user action?)
Second problem is in the addPolygonOverlay method. You have to use the NSArray count property to get the number of items in the array. The sizeof function returns the number of bytes of physical memory the passed variable uses. For ptsArray which is a pointer, it will return 4. If the ptsArray has less than 4 items, you will get the "index out of range" exception.
So change
int cornersNumber = sizeof(ptsArray);
to
int cornersNumber = ptsArray.count;
Another important thing to note is that the polygon sides will be drawn in the order the points are in the array. If the user does not add corners in a clockwise or counter-clockwise order, the polygon will look strange. You could re-create the polygon overlay immediately after a user adds/removes an annotation so they get immediate feedback on how it will look.

Accessing methods from another class

I am new to the C objective and I'm having lots of difficulties. Hope you goys would be able to help me out.
Alright, I have a view controller class that displays the data from the external sensor plugged to an iphone. I have another database class that is supposed to grab that data and store it in an array which can be used to plot a graph.
I'm having difficulties in finding a way to capture the data captured by the view controller class method variables and using it to store in database class.
The code below is from View Controller class which captures analog signal and displays in UILabel.
(void) forceCalculationKg{
NSNumber *number = [controller. analogInValues objectAtIndex:0];
[controller enableDigitalInputs:YES];
double value = [number doubleValue];
double force;
force = 0.2908 *pow(2.718,(1.2089 * value));
double forcekg;
forcekg = force/2.2;
forceoutput.text = [NSString stringWithFormat:#" %0.1f", forcekg];
}
You didn't submit code for this question that actually compiles. But in any case, I assume your forceCalculationKg method is the function on your controller that you are calling to retrieve the sensor data? You are then applying a calculation to the data and displaying it, right?. To keep this data around, just add a NSMutableArray property to your controller and save each transformed data point to it.
-(void) forceCalculationKg {
NSNumber *number = [controller.analogInValues objectAtIndex:0];
[controller enableDigitalInputs:YES];
double value = [number doubleValue];
double force = 0.2908 *pow(2.718,(1.2089 * value));
double forcekg = force/2.2;
[self.datapoints addObject: [NSNumber numberWithDouble: forcekg]];
forceoutput.text = [NSString stringWithFormat:#" %0.1f", forcekg];
}
Where datapoints is a NSMutableArray property you add to your view controller via the #property and #synthesize keywords. You can then pass the datapoints array around your program to wherever you need it.

Adding item to NSMutableArray with function results in no

I have the following utility method declared, where "players" is a NSMutableArray object and a property of my application's view controller. My problem is that "players" still has 0 objects after this method is called.
-(void)addPlayerNamed:(NSString *)name withLife:(NSNumber *)life{
NSMutableDictionary *newPlayer = [NSMutableDictionary dictionaryWithCapacity:1];
[newPlayer setObject:life forKey:name];
[players addObject:newPlayer];
}
Have you set players to anything? You have to call this before using it, maybe in the initialiser.
players=[[NSMutableArray alloc] init];
If players is a property, you probably also want to use
self.players
instead of
players
(Although the latter will still work)
In all likelihood, players is nil. Any message to nil returns 0 or nil.