Get variable or object from IBAction method - iphone

I have been reading, googling and watching Lynda videos to find the answer for this the last couple days. I haven't found a good answer yet.
This seems like it should be pretty simple. With normal methods I can pass variables. But with IBAction being (void) I cant figure out how to get a variable to another method.
Here are some simple examples of what I would like to do:
- (IBAction)treeButton:(id)sender {
int test = 10;
}
-(void)myMethod{
NSLog(#"the value of test is %i",test);
}
This what I really want to have work. I am try to have a button set the initial location that I want to store and use in another method.
- (IBAction)locationButton:(id)sender {
CLLocation *loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
}
-(void)myMethod{
NSLog(#"the value of test is %i",test);
NSLog(#"location 1 is %#",loc1);
}
Any suggestions to lead me in the right direction would be great. I have read and watched videos on variable scope, instance varaibles etc. Just not understanding what I need to do here

Change myMethod to accept the parameters you need:
- (void)myMethod:(CLLocation *)location {
NSLog(#"location 1 is %#", location);
}
Invoke it something like so:
- (IBAction)locationButton:(id)sender {
CLLocation *loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
[self myMethod:loc1];
}
If you need it to be accessible by multiple methods or at different points in the code, I recommend creating an instance variable for loc1 in your #interface declaration.
#interface MyClass : NSObject {
CLLocation *loc1;
}
In your method, instead of re-declaring it, you'd just set it:
loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
In myMethod, just access it:
- (void)myMethod{
NSLog(#"location 1 is %#", loc1);
}

Related

MKReverseGeocoder: where is location string stored?

I found this tutorial:
http://evilrockhopper.com/2010/01/iphone-development-reverse-geocoding/
and implemented this code:
if (reverseGeocoder != nil)
{
// release the existing reverse geocoder to stop it running
[reverseGeocoder release];
}
// use whatever lat / long values or CLLocationCoordinate2D you like here.
CLLocationCoordinate2D locationToLookup = {52.0,0};
MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:locationToLookup];
reverseGeocoder.delegate = self;
[reverseGeocoder start];
The question is, when I started reverseGeocoding, where is location string stored?
I have coordinate and I give them to reverseCeocoder to find me address, but how to get this address in some string for example?
Just read the documentation for MKReverseGeocoder:
The reverse geocoder returns information through its associated delegate object, which is an object that conforms to the MKReverseGeocoderDelegate protocol.
So you have to implement these two methods in your delegate:
– reverseGeocoder:didFindPlacemark:
– reverseGeocoder:didFailWithError:
and the geocoder will call them when it has information for you.

NSMutableArray of ClLocationCoordinate2D

I'm trying to create then retrieve an array of CLLocationCoordinate2D objects, but for some reason the array is always empty.
I have:
NSMutableArray *currentlyDisplayedTowers;
CLLocationCoordinate2D new_coordinate = { currentTowerLocation.latitude, currentTowerLocation.longitude };
[currentlyDisplayedTowers addObject:[NSData dataWithBytes:&new_coordinate length:sizeof(new_coordinate)] ];
I've also tried this for adding the data:
[currentlyDisplayedTowers addObject:[NSValue value:&new_coordinate withObjCType:#encode(struct CLLocationCoordinate2D)] ];
And either way, the [currentlyDisplayedTowers count] always returns zero. Any ideas what might be going wrong?
Thanks!
To stay in object land, you could create instances of CLLocation and add those to the mutable array.
CLLocation *towerLocation = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
[currentDisplayedTowers addObject:towerLocation];
To get the CLLocationCoordinate struct back from CLLocation, call coordinate on the object.
CLLocationCoordinate2D coord = [[currentDisplayedTowers lastObject] coordinate];
As SB said, make sure your array is allocated and initialized.
You’ll also probably want to use NSValue wrapping as in your second code snippet. Then decoding is as simple as:
NSValue *wrappedCoordinates = [currentlyDisplayedTowers lastObject]; // or whatever object you wish to grab
CLLocationCoordinate2D coordinates;
[wrappedCoordinates getValue:&coordinates];
You need to allocate your array.
NSMutableArray* currentlyDisplayedTowers = [[NSMutableArray alloc] init];
Then you can use it. Be sure to call release when you are done with it or use another factory method.
I had currentlyDisplayedTowers = nil which was causing all the problems. Also, the previous advice to init and alloc were necessary. Thanks everyone for the help!
For anyone else with this issue, there's another solution if you are planning on using MapKit.
(The reason I say IF, of course, is because importing a module such as MapKit purely for a convenient wrapper method is probably not the best move.. but nonetheless here you go.)
#import MapKit;
Then just use MapKit's coordinate value wrapper whenever you need to:
[coordinateArray addObject:[NSValue valueWithMKCoordinate:coordinateToAdd]];
In your example..
[currentlyDisplayedTowers addObject:[NSValue valueWithMKCoordinate:new_coordinate]];

Iphone application. Crash without the self keyword

I will try to make myself as clear as possible. Let start from the beginning. I have an application with a tableview that contains a list of places with distances from myLocation. Now everytime I get an update in the gps location I run the following code
- (void)locationUpdate:(CLLocation *)location {
myLocation = location;
for (Trek * trek in list) {
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[trek latitude_start] longitude:[trek longitude_start]];
double dis = [locationManager getDistance: loc];
[trek setDistance:dis];
[trek setDistanceUnit];
[loc release];
}
[self.tableView reloadData];
}
Now this piece of code [trek setDistanceUnit]; calls
-(void) setDistanceUnit {
if (self.distance < 1000.0)
self.distanceString = [NSString stringWithFormat:#"%.0lf m", self.distance];
}
Now if I use only distanceString the application crash. Now I think it may have something to do with the fact that those updates may run concurrently (in parallel) to the access required by the view to draw the cells. Anyone has any idea? I can post more code if helpful, I just didn't want to post too much to make this post too long.
I tried to search everywhere but I could not found anything so far.
Thanks in advance,
Umberto
PS Now the application is working but I would like to understand what is going on.
If your distanceString is a retain property, assigning it without self sets it up for a crash because you bypass the setter, and assign the string without retaining it. So when the string gets deallocated on being sent to the autorelease pool, your app crashes.
By synthesizing the accessors using #synthesize and using the dot notation (or setDistanceString:), the object will retain the string for you so that it always has a pointer to it for itself (until it's released).

Sharing variables amongst 2 ViewControllers

Here is a simple one for you guys . I'm defining a class to store variables in so I can reuse those variables in different ViewControllers .
Here is how I do it, it`s obviously not working ( that's why I'm asking a question ... ):
I declare a class :
VariableStore.h
#interface VariableStore : NSObject {
int evTe;
}
#property (nonatomic) int evTe;
+ (VariableStore *)shareInstance;
#end
VariableStore.m
#implementation VariableStore
#synthesize evTe;
+ (VariableStore *)sharedInstance {
static VariableStore *myInstance = nil;
return myInstance;
}
#end
Now in my FirstViewController I want to set the value for evTe :
[[VariableStore sharedInstance] setEvte:2];
NSLog(#"value testing, %i", evTe);
And this keeps on returning 0 unfortunately, Im obviously missing something important here but I can't figure out what it is .
Later on Id like to set the value for evTe here in the FirstViewController and then reuse it back in the SecondViewController ..
You are setting your shared instance to nil and then returning it:
static VariableStore *myInstance = nil;
return myInstance;
A nil instance won't hold your variable. It's nil.
First off you shouldn't be using a singleton to pass around variables. If you're going to do that then you might as well just use global variables instead (don't do that either by, the way). Second, if you insist on using a singleton, you need to read up on how to use them.
Finally, if you want to pass variables between view controllers, you either need another view controller that is a parent to the two to facilitate passing data between them, or one needs to call the other and take the first one or its data as a parameter.
Well, you're asking for the value of evTe without calling the object to which it belongs. Try this:
NSLog(#"value testing, %i", [[VariableStore sharedInstance] evTe]);
If you keep using the singleton for a number of times, you might want to do:
VariableStore *vStore = [VariableStore sharedInstance];
so you can do:
[vStore setEvTe:2];
NSLog(#"value testing, %i", [vStore evTe]);
And look out for what Matt said about nilling your singleton ;)
I think in nslog you should output not just evTe, but [[VariableStore sharedInstance] evTe].
First, you have to declare the static variable outside the function, in a way both controllers can access.
static VariableStore* myInstance = nil;
The singleton sharedInstance should be:
if(myInstance == nil)
{
myInstance = [[VariableStore] alloc] init];
}
return myInstance;

Delay the call to the delegate method - mapView:regionDidChangeAnimated:

Whenever the user scrolls map or zooms in/out, this method gets called instantaneously. I want to delay the call to this method by say 2 secs. Is it possible to do that?
You could implement that method like this:
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSNumber *animatedNumber = [NSNumber numberWithBool:animated];
NSArray *args = [[NSArray alloc] initWithObjects:mapView,
animatedNumber,nil];
[self performSelector:#selector(delayedMapViewRegionDidChangeAnimated:)
withObject:args
afterDelay:2.0f];
[args release];
}
Then, somewhere in the same class:
-(void)delayedMapViewRegionDidChangeAnimated:(NSArray *)args
{
MKMapView *mapView = [args objectAtIndex:0];
BOOL animated = [[args objectAtIndex:1] boolValue];
// do what you would have done in mapView:regionDidChangeAnimated: here
}
Of course, if you don't need one of those arguments (either mapView or animated), you could make this considerably simpler by only passing the one you did need.
If you can't just edit the code for your MKMapViewDelegate, perhaps you could do something similar with method swizzling, although then you're getting really hacky.
You can send a delayed message with performSelector:withObject:afterDelay: or one of its related methods.