mapkit and annotations - iphone

I am very new to XCode and iPhone development so please bear with me if this question is too simple. But I have a map and I have successfully added images (not pins) to it for my annotations. And I can change the image when the user selects one of the annotations.
I created a class that inherits from MKAnnotationView with the following methods:-
- (id)initWithAnnotation:
- (void)setAnnotation:
- (void)drawRect:
and I am using
- (void)touchesBegan
to know when an annotation has been selected. And in touchesBegan I am doing :-
UIImage *i = [UIImage imageNamed:#"A.png"];
self.image = i;
to change the image. But what I am really stumped on is how do I change the image back to it's original image when the users selects the next annotation. I have tried:-
NSArray *selectedAnnotations = map.selectedAnnotations;
for(id annotationView in selectedAnnotations) {
[map deselectAnnotation:[annotationView annotation] animated:NO];
}
but it errors
and I tried
for (MKAnnotationView *ann in map.selectedAnnotations){
if ([ann isMemberOfClass:[Place class]])
{
place = (Place *)ann;
NSLog(#"second = %#"#" %f"#" %f", place.title, place.longitude, place.latitude);
if (currentPlaceID == place.placeID) {
//UIImage *i = [UIImage imageNamed:#"A.png"];
//ann.image = i;
}
else {
UIImage *i = [UIImage imageNamed:#"pin.png"];
ann.image = i;
}
}
}
the above code works ok until I get to ann.image = i; then it errors. The errors I get are:-
*** -[Place setImage:]: unrecognized selector sent to instance 0x4514370
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[Place setImage:]: unrecognized selector sent to instance 0x4514370'
Yes I can see that my place object does not have an image so that's why it is going wrong. But if I create an image property on my place object - how will that change the annotations image which what I am trying to do.
Please advise as I have been going around in circles on this one for 2 days now!!!!
Thanks in advance
Cheryl

Cheryl,
I don't completely follow what you're trying to do, but here are some thoughts:
Here's what I would do to restore the original image:
In your subclass of MKAnnotationView, add two UIImage Properties,
firstImage and secondImage, set up to retain.
When you init the annotation view, set up both images. (At the point where you assign the image to your annotation view, also save it to your new firstImage property)
Then, you can say
self.image = firstImage;
or
self.image = secondImage.
That will swap the appropriate image into place, while keeping the other image around to restore.
Your code:
NSArray *selectedAnnotations = map.selectedAnnotations; for(id annotationView in selectedAnnotations) { [map
deselectAnnotation:[annotationView annotation] animated:NO]; }
is not right. It asks the map for an array of annotations, and then treats them as annotation VIEWs.
An annotation is a data model object. It contains the data describing an annotation.
An annotation VIEW object is a temporary display object used to display an annotation on the map if it is currently visible. There are not always annotation views for every annotation on the map.

Related

UIImageView weird image property issue

I'm dealing with a super easy task that somehow introducing some difficulties...
All I'm trying to do is to create a view controller and set its UIImageView's image property to some image.
When I try to that, I get nil =\
GenericViewController *genericViewController = [[GenericViewController alloc] init];
UIImage *image = [UIImage imageNamed:#"Camera.png"];
genericViewController.genericImageView.image = image;
NSLog(#"%#", genericViewController.genericImageView.image);
Output: (null)
I imagine genericImageView is set up either in a nib or in the -loadView method. However, at the point in which you're trying to access the image view, the view for the VC hasn't been loaded yet. The quick fix is to call
(void)genericViewController.view;
before accessing genericImageView. This will force the view to load. The "better" approach would be to give genericViewController an image property that you assign to, then in its setter you can say
- (void)setGenericImage:(UIImage *)image {
if (_genericImage != image) {
[_genericImage release];
_genericImage = [image retain];
if ([self isViewLoaded]) {
self.genericImageView.image = image;
}
}
}
and in -viewDidLoad you can say
- (void)viewDidLoad {
[super viewDidLoad];
self.genericImageView.image = self.genericImage;
}
This method, besides being more modular and architecturally-sound, also has the advantage where if the view controller's view is unloaded (say, another view is pushed onto the nav stack and a memory warning comes along), when it gets re-loaded it will still have the image.

Annotation Sub Class custom initWithCoordinate

I've subclassed MKAnnotation so that i can assign objects to each annotation, this is so that when the rightCalloutAccessoryView is clicked i can push a navigation controller with the object passed to it and display the objects data in another view.
This all works great apart from one thing, i've extended upon initWithCoordinate like so:
-(id)initWithCoordinate:(CLLocationCoordinate2D)coord andObject:(NSManagedObject *)object {
[self setPlace:object];
coordinate = coord;
title = [place valueForKey:#"name"];
subtitle = [place valueForKey:#"address"];
return self;
}
Although everything is working great i'm recieving the warning:
NO '-initWithCoordinate:andObject:' method found
Which means i'm doing something wrong somewhere, what is the correct way to go about adding upon initWithCoorinate?
Put the prototype -(id)initWithCoordinate:(CLLocationCoordinate2D)coord andObject:(NSManagedObject *)object in .h file.

Memory problem with properties in objective-c

UIImage *image = [[UIImage alloc] initWithData:data];
((YKSubCategory *)[_subCategories objectAtIndex:connection.tag - 1]).menuImage = image;
[image release];
Here is the code I've written. The data is exists and the designed image is created. (I've tested it with an imageview and the image appears).
The problem comes when I try to set the menuImage property. It will not be set. I don't know why. So the value of the menuImage property remains nil.
Here is the property definition:
#property (nonatomic, retain) UIImage *menuImage;
What can be the problem?
Edit:
I've divided the code for the request of walkytalky.
Here is the code I've written:
UIImage *image = [[UIImage alloc] initWithData:data];
YKSubCategory *subCategory = (YKSubCategory *)[_subCategories objectAtIndex:connection.tag - 1];
subCategory.menuImage = image;
[image release];
[_tableView reloadData];
So now the funny thing is that the subCategory variable is the variable what I expect. Then after I set the menuImage property then the variable for this property is set. I can see in the debugger, but in the array isn't set. What is this?
(i) Have you #synthesize-d menuImage?
(ii) Can you break up the setter line to first get the YKSubCategory object and test it exists and is what you expect?
YKSubCategory* target = (YKSubCategory*)[_subCategories objectAtIndex:connection.tag - 1];
NSLog("subcategory target = %#", target);
// other tests here
target.menuImage = image;
Otherwise, I don't think we have enough info to solve this. What does menuImage look like immediately after setting?
EDIT: when you say "in the array isn't set", do you mean that the actual object in the array differs from the one you've just set right there and then? Or that when you come back to the array when loading the table data the menuImage is no longer set? Or that it just doesn't show in the table?
The first seems impossible on the face of it, so let's think about the second and third.
If menuImage has been reset by the time you come back to it, there must be some code setting it somewhere. This may not go through the property accessor, but for starters you might explicitly implement the setter to log the changes:
- (void) setMenuImage:(UIImage*)newImage
{
if ( newImage != menuImage )
{
NSLog(#"Changing menuImage from %# to %#", menuImage, newImage);
[newImage retain];
[menuImage release];
menuImage = newImage;
}
}
Another possibility is that the actual YKSubCategory object in the array has changed, or even that the arrays are different, so check that the pointers are the same in both locations.
On the other hand, if the menu image ivar is set, but it's not showing up in the table, you need to check your drawing code.

iPhone Dev = maps and deselecting annotations

I am successfully drawing annotations on a map using an array of annotations. I can even click on the annotation and change it’s colour or image. My problem arises when the use selects the second annotation and I want to dynamically change the colour or image of the first one back to a non-selected colour/image. I can get the array of all the annotations and work through the array but once I try to set the colour or image ot the array I get a similar error.
for (MKAnnotationView *ann in map.selectedAnnotations){
if ([ann isMemberOfClass:[Place class]]) {
place = (Place *)ann;
if (currentPlaceID != place.placeID) {
UIImage *i = [UIImage imageNamed:#"pin.png"];
ann.image = i;
}
}
the above code works ok until I get to ann.image = i; then it errors. The errors I get are:-
-[Place setImage:]: unrecognized selector sent to instance 0x4514370 Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '** -[Place setImage:]:
unrecognized selector sent to instance 0x4514370'
Please advise as I have been going around in circles on this one for 2 days now!!!!
Any ideas on how best to do this?
thanks in advance
Do you have a property on the class Place called image?
Something like... #property (nonatomic, retain) UIImage* image; and is it properly synthesized? #synthesize image;?
The error is pretty straight forward, some object is receiving a message that it doesn't respond to, namely 'setImage' which is invoked by the .image.
Here is your code:
1. for (MKAnnotationView *ann in map.selectedAnnotations) {
2. if ([ann isMemberOfClass:[Place class]]) {
3. place = (Place *)ann;
4. if (currentPlaceID != place.placeID) {
5. UIImage *i = [UIImage imageNamed:#"pin.png"];
6. ann.image = i;
7. }
8. }
9. }
What I can see:
ann is an MKAnnotationView (from map.selectedAnnotations)
you are typecasting your annotation to a place on line 3 (is this right? Does Place subclass MKAnnotationView?)
you are properly setting the image to the annotation
What this means:
If Place is indeed a subclass of MKAnnotationView, you hid the setImage (somehow) method
If Place is NOT a subclass of MKAnnotationView, you've added an invalid annotation to the annotations (sure) that you're trying to treat as an annotation.
I finally figured out how to do this. As usual it's not that hard once you know how. Just thought I would pass this on.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
NSLog(#"here I am in set selected");
if (YES == selected)
{
NSLog(#"I am selected");
}
else
{
self.backgroundColor = [UIColor clearColor];
NSLog(#"not selected");
}
}

Using a variable in a statement to reference the image stored in a UIImageView

UPDATED Scroll down to see the question re-asked more clearly....
If I had the name of a particular UIImageView (IBOutlet) stored in a variable, how can I use it to change the image that is displayed. I tried this, but it does not work.
I'm still new to iphone programming, so any help would be appreciated.
NSString *TmpImage = #"0.png";
NSString *Tst = #"si1_1_2";
TmpImage = #"1.png";
UIImage *sampleimage = [[UIImage imageNamed:TmpImage] retain];
((UIImageView *) (Tst)).image = sampleimage; // This is the line in question
[sampleimage release];
RESTATED:
I have a bunch of images on the screen.... UIImageView *s1, *s2 ,*s3 etc up to *s10
Now suppose I want to update the image each displays to the same image.
Rather than doing
s1.image = sampleimage;
s2.image = sampleimage;
:
s10.image = sampleimage;
How could i write a for loop to go from 1 to 10 and then use
the loop var as part of the line that updates the image.
Something like this.
for ( i = 1; i <- 10; ++i )
s(i).image = sample; // I know that does not work
Basic question is how do I incorporate the variable as part of the statement to access the image? Don't get hung up on my example. The main question is how to use a variable as part of the access to some element/object.
Bottom Line... If I can build the name of a UIImageView into a NSString object, How can I then use that NSString object to manipulate the UIImageView.
Thanks!
Ugh! Your line in question:
((UIImageView *) (Tst)).image = sampleimage;
is casting a string pointer as a UIImageView pointer - you're basically saying that your pointer to a string is actually a pointer to a UIImageView! It will compile (because the compiler will accept your assertion happily) but will of course crash on running.
You need to declare a variable of type UIImageView. This can then hold whichever view you want to set the image of. So your code could look like the following:
NSString *TmpImage = #"0.png";
UIImageView *myImageView;
If (someCondition == YES) {
myImageView = si1_1_2; //Assuming this is the name of your UIImageView
} else {
myImageView = si1_1_3; //etc
}
UIImage *sampleimage = [UIImage imageNamed:TmpImage]; //no need to retain it
myImageView.image = sampleImage;
Hopefully this makes sense!
Edit: I should add, why are you trying to have multiple UIImageViews? Because a UIImageView's image can be changed at any time (and in fact can hold many), would it not be better to have merely one UIImageView and just change the image in it?