MapView Problems - Pin change color when map reloded - xcode

I have a problem with the PIn color mapView when a refresh is done.
In my I app i display some point with two color in order to identify if a service is available.
On the first start, no problems appear. The code is the follower:
- (void)viewDidLoad
{
[super viewDidLoad];
[self dowloadPoint]; // here I exucte the first start
}
- (void)dowloadPoint{
NSURL *url1 =[NSURL URLWithString:#"http:MYUSRL"];
NSData *datos1 =[[NSData alloc] initWithContentsOfURL:url1];
[self plotBarPosition:datos_string1]; //Here I call the plotBarPosition method
}
- (void)plotBarPosition:(NSString *)datos_string1 {
for (id<MKAnnotation> annotation in _mapView.annotations) {
[_mapView removeAnnotation:annotation];
}
// Parse the string into JSON
NSDictionary *json = [(NSDictionary*)[datos_string1 JSONValue]objectForKey:#"features"];
// Get the objects you want, e.g. output the second item's client id
NSArray *items_properties = [json valueForKeyPath:#"properties"];
NSArray *items_geo = [json valueForKeyPath:#"geometry"];
for (int i = 0; i < [json count]; i++){
NSString *nomprePunto =[[items_properties objectAtIndex:i] objectForKey:#"title"];
NSNumber *lat =[[[items_geo objectAtIndex:i] objectForKey:#"coordinates"] objectAtIndex:0];
NSNumber *lon =[[[items_geo objectAtIndex:i] objectForKey:#"coordinates"] objectAtIndex:1];
CLLocationCoordinate2D coordinate;
coordinate.latitude = lat.doubleValue;
coordinate.longitude = lon.doubleValue;
//ESTADO
NSString *description = [[items_properties objectAtIndex:i] objectForKey:#"description"];
NSString *estado_punto = [[NSString alloc]init];
if ([description rangeOfString:#"Averiado"].location == NSNotFound) {
estado_punto = #"Available";
} else {
estado_punto = #"NOt Available";
averiados ++;
}
NSString *averiadosStr = [NSString stringWithFormat:#"%d",averiados];
averiadosLabel.text = averiadosStr;
MyLocation *location =[[MyLocation alloc] initWithName:nomprePunto coordinate:coordinate estado:estado_punto];
[_mapView addAnnotation:location];
}
}
- (MKPinAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(MyLocation *)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
if([[annotation estado] isEqualToString:#"En Servicio"])
annotationView.pinColor = MKPinAnnotationColorGreen;
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
But whe I add a refres button that is function is simply a refreshcalling the dowloadPoint once again,
- (IBAction)refresh{
[self dowloadPoint];
}
the color of pins change in a "random manner", not corrisponding with the real state of point.
Any ideas about what is happening? Thanks in advance.
EDIT: It seemps pproblems is due to:
for (id<MKAnnotation> annotation in _mapView.annotations) {
[_mapView removeAnnotation:annotation];
}
erasing it, the app work properly but pins area drown abow the previous ones...:S

The default color of the pin is red. You set it to green if the estado property of your MyLocation object is equal to #"En Servicio". I understand that sometimes the color is red, when your estado property is equal to #"En Servicio", or sometimes green when it is not.
One reason could be that your MyLocation object simply does no longer exist when you press the refresh button. In this case, you might still have a pointer to the memory location where it once existed, but this location may have been overwritten by anything, causing a random color.
This can happen e.g. if your MyLocation object has been created as an autorelease object that has been released when you returned to the main event loop, i.e. to handle user interactions.
This should not be the case if you are using ARC.

Related

Several Hyperlinks in NSTableView Cell

At the moment I have an NSTableView with a custom NSTextFieldCell that holds an NSAttributedString with some ranges with the NSLinkAttribute. I tried to integrate code from Apple's TableViewLinks example and Toomas Vather's HyperlinkTextField.
I implemented the -trackMouse Function like this:
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag {
BOOL result = YES;
NSUInteger hitTestResult = [self hitTestForEvent:theEvent inRect:cellFrame ofView:controlView];
if ((hitTestResult & NSCellHitContentArea) != 0) {
result = [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:flag];
theEvent = [NSApp currentEvent];
hitTestResult = [self hitTestForEvent:theEvent inRect:cellFrame ofView:controlView];
if ((hitTestResult & NSCellHitContentArea) != 0) {
NSAttributedString* attrValue = [self.objectValues objectForKey:#"theAttributedString"];
NSMutableAttributedString* attributedStringWithLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attrValue];
//HOW TO GET A RIGHT INDEX?
NSTableView* myTableView = (NSTableView *)[self controlView];
NSPoint eventPoint = [myTableView convertPoint:[theEvent locationInWindow] fromView:nil];
NSInteger myRow = [myTableView rowAtPoint:eventPoint];
NSRect myBetterViewRect = [myTableView rectOfRow:myRow];
__block NSTextView* myTextView = [[NSTextView alloc] initWithFrame:myBetterViewRect];
[myTextView.textStorage setAttributedString:attributedStringWithLinks];
NSPoint localPoint = [myTextView convertPoint:eventPoint fromView:myTableView];
NSUInteger index = [myTextView.layoutManager characterIndexForPoint:localPoint inTextContainer:myTextView.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
if (index != NSNotFound)
{
NSMutableArray* myHyperlinkInfos = [[NSMutableArray alloc] init];
NSRange stringRange = NSMakeRange(0, [attrValue length]);
[attrValue enumerateAttribute:NSLinkAttributeName inRange:stringRange options:0 usingBlock:^(id value, NSRange range, BOOL* stop)
{
if (value)
{
NSUInteger rectCount = 0;
NSRectArray rectArray = [myTextView.layoutManager rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer:myTextView.textContainer rectCount:&rectCount];
for (NSUInteger i = 0; i < rectCount; i++)
{
[myHyperlinkInfos addObject:#{kHyperlinkInfoCharacterRangeKey : [NSValue valueWithRange:range], kHyperlinkInfoURLKey : value, kHyperlinkInfoRectKey : [NSValue valueWithRect:rectArray[i]]}];
}
}
}];
for (NSDictionary* info in myHyperlinkInfos)
{
NSRange range = [[info objectForKey:kHyperlinkInfoCharacterRangeKey] rangeValue];
if (NSLocationInRange(index, range))
{
NSURL* url = [NSURL URLWithString:[info objectForKey:kHyperlinkInfoURLKey]];
[[NSWorkspace sharedWorkspace] openURL:url];
}
}
}
}
}
return result;}
The character-Index when clicking into the cell's (nstextview's) text appears not to fit. So even if there are more than one link in the text, usually the last link is opened. My guess is that I donĀ“t get the nsrect of the clicked cell. If so, how could I get the right NSRect?
I am glad for any suggestions, comments, code pieces - or simpler solutions (even if this would include switching to a view-based tableview).
Thanks.

Manage memory allocation issue on Map iOS

In my iPhone app I have a map view. In this I am displaying a number of pin views depends on the data from a web server. Here is the method I used for it.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSString *identifier = #"myPin";
self.pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (self.pinView == nil) {
self.pinView= [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]autorelease]; //11.1%
} else {
self.pinView.annotation = annotation;
}
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; //20.4%
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
self.pinView.rightCalloutAccessoryView = rightButton; //2.7%
MyAnnotation *annot = (MyAnnotation*)annotation;
UIImageView *egoimageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"defaultPerson"]]; //17.5%
NSString *imageUrl = [NSString stringWithFormat:#"%#%#", CommonImageURL, [friendsProfileImageArray objectAtIndex:annot.tag]]; //9.4%
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&
([UIScreen mainScreen].scale == 2.0)) {
// Retina display
[egoimageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"defaultPerson#2x.png"]]; //2.6%
egoimageView.image = [UIImage imageWithCGImage:egoimageView.image.CGImage scale:egoimageView.image.size.width/25 orientation:egoimageView.image.imageOrientation];
} else {
// non-Retina display
[egoimageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"defaultPerson.png"]]; //14.6%
egoimageView.image = [UIImage imageWithCGImage:egoimageView.image.CGImage scale:egoimageView.image.size.width/25 orientation:egoimageView.image.imageOrientation]; //1.6%
}
[egoimageView sizeToFit];
self.pinView.leftCalloutAccessoryView = egoimageView; //3.1%
[egoimageView release];
self.pinView.canShowCallout=YES;
self.pinView.animatesDrop=YES;
//pin color based on status.....
if ([annot.relationshipStatus intValue]==2 )
self.pinView.pinColor=MKPinAnnotationColorGreen;
else
self.pinView.pinColor=MKPinAnnotationColorPurple; //17.1%
return self.pinView;
}
In this I have mentioned the percentage of memory allocations. If I continuously load the map, the total memory usage increases and the app crashes. How can I properly fix this? I have tried to fix it, but I don't know what more I can do.
Please help, thanks in advance.

access an UIImage instance variable and display it in UIImageView

I'm trying to access an UIImage instance variable and display it in UIImageView. When I try to NSLog the path I get null. I can manually display a pic through the IB, but I want to do this strictly through code
#import "Deck.h"
#import "Card.h"
#implementation Deck
#synthesize cards;
- (id) init
{
if(self = [super init])
{
cards = [[NSMutableArray alloc] init];
NSInteger aCount, picNum = 0;
for(int suit = 0; suit < 4; suit++)
{
for(int face = 1; face < 14; face++, picNum++)
{
NSString *fileName = [NSString stringWithFormat:#"card_%d", picNum];
NSString *path = [[NSBundle mainBundle] pathForResource:fileName
ofType:#"png"inDirectory:#"/cards"];
NSLog(#"%#", path); //outputs correctly
UIImage *output = [UIImage imageNamed:path];
NSLog(#"%#", output); //outputs null
Card *card = [[Card alloc] initWithFaceValue:(NSInteger)face
countValue:(NSInteger)aCount
suit:(Suit)suit
cardImage:(UIImage *)output];
[cards addObject:card];
}
}
}
return self;
}
I've added a link to show where the pics are found
Link
You don't have to include all the path to the image, if you just put the name, Xcode will automatically look for it.

Cocos2d populate layer based on menu in a different layer

I'm working on a species ID app and would like to populate a layer with sprites based on which animal you select on the main layer. I've made each animal a menu item, and can get my info layer to appear when pressing the button, but how can I set it up so the layer shows the right data depending on which animal you select? The info layer is not a full screen layer, but rather an overlaying layer that only fills about 75% of the screen, which is why I'm going with a layer rather than a scene. I know I can create a new layer for each animal (approx 50) and code it so each button calls its own layer, but I think populating based on which button is pressed would make for cleaner code. If flamingoButton is pressed, sprite is filled with flamingo.png and label is populated with flamingo information. How do I get my info layer to listen to the buttons on the main layer?
MainLayer.m code:
-(id) init
{
if( (self=[super init]))
{
CCMenuItemImage *flamingoButton = [CCMenuItemImage itemFromNormalImage:#"Explore-sign.png" selectedImage:#"Explore-sign.png" target:self selector:#selector(showSecondLayer:)];
flamingoButton.position = CGPointMake(0, 60);
flamingoButton.tag = 101;
CCMenu *menu = [CCMenu menuWithItems:flamingoButton, nil];
[self addChild:menu];
}
return self;
}
-(void) showSecondLayer: (id) sender
{
CCMenuItemImage *item = (CCMenuItemImage *) sender;
int itemID = item.tag;
secondLayer = [SecondLayer node];
secondLayer.position = CGPointMake(0, 700);
[self addChild:secondLayer];
CCMoveTo *moveLayer = [CCMoveTo actionWithDuration:1.0 position:CGPointMake(0, 0)];
[secondLayer runAction:moveLayer];
}
SecondLayer.m (the info layer)
-(id) init
{
if( (self=[super init]))
{
//Change this sprite image based on button from main layer. I don't have it coded in yet, but I understand the concept of putting a variable in the file string using %# or %d
CCSprite *infoCard = [CCSprite spriteWithFile:#"species1.png"];
infoCard.anchorPoint = CGPointMake(0.5, 0);
infoCard.position = CGPointMake(512, 0);
[self addChild:infoCard];
}
return self;
}
Ok, this might work:
//MainLayer:
-(id) init
{
if( (self=[super init]))
{
CCMenuItem *flamingoButton = [CCMenuItemImage itemFromNormalImage:#"Explore-sign.png"
selectedImage:#"Explore-sign.png"
target:self
selector:#selector(showSecondLayer:)];
flamingoButton.position = ccp(0, 60);
flamingoButton.tag = 1;
CCMenu *menu = [CCMenu menuWithItems:flamingoButton, nil];
[self addChild:menu];
}
return self;
}
-(void) showSecondLayer: (CCMenuItem*) sender
{
secondLayer = [SecondLayer layerWithTag:[sender tag]];
secondLayer.position = ccp(0, 700);
[self addChild:secondLayer];
CCMoveTo *moveLayer = [CCMoveTo actionWithDuration:1.0 position:ccp(0, 0)];
[secondLayer runAction:moveLayer];
}
//Second Layer.h
+(id)layerWithTag:(NSInteger)aTag;
-(id) initWithTag:(NSInteger)aTag;
//Second Layer.m:
+(id)layerWithTag:(NSInteger)aTag {
return [[[SecondLayer alloc] initWithTag:aTag] autorelease];
}
-(id) initWithTag:(NSInteger)aTag
{
if( (self=[super init]))
{
//Change this sprite image based on button from main layer. I don't have it coded in yet, but I understand the concept of putting a variable in the file string using %# or %d
CCSprite *infoCard = [CCSprite spriteWithFile:[NSString stringWithFormat:#"species%d.png", aTag]];
infoCard.anchorPoint = ccp(0.5, 0);
infoCard.position = ccp(512, 0);
[self addChild:infoCard];
}
return self;
}
EDIT:
Even though the previous solution works, it's not intuitive, and I feel I am breaking some OOP concepts. Most importantly, it is only useable given that your info about the animal can be retrieved using a single int! .. Using it this way is a BIT better, it's totally up to you to decide:
Ehm, so, I would suggest you set up an Entity Class first:
//AnimalResources.h
#import "Blahblahblah"
//Give it a good name, I was always bad at Science:
#interface AnimalResources {
//load all your properties:
NSString* info;
CCSprite* sprite;
...
}
//set the properties as needed:
//Make sure you properly manage this!! It is retained!
#property (nonatomic, retain) CCSprite* sprite;
...
//method prototype (signature.. am not sure)
//Now, we shall build on the fact that it will be easy for you to map an integer to the right resources:
+(id)animalResourcesWithTag:(NSInteger)aTag;
-(id)initAnimalResourcesWithTag:(NSInteger)aTag;
//AnimalResources.m:'
#synthesize sprite, ... ;
+(id)animalResourcesWithTag:(NSInteger)aTag {
[[[AnimalResources alloc] initAnimalResourcesWithTag:aTag] autorelease];
}
-(id)initAnimalResourcesWithTag:(NSInteger)aTag {
if ((self = [super init])) {
//use tag to retrieve the resources:
//might use the stringFormat + %d approach, or have a dictionary/array plist, that maps an int to a dictionary of resource keys.
//string way of doing things:
self.sprite = [CCSprite spriteWithFile:[NSString stringWithFormat:#"species%d.png", aTag]];
...
//Dictionary: dict/array is an NSDictionary/NSArray read from disk sometime. Don't read it here, since it
//will read the file from disk many times if you do --> BAD. I could explain a rough way to do that if you
//need help
animalDict = [dict objectForKey:[NSString stringWithFormat:#"species%d.png", aTag]];
//OR...
animalDict = [array objectAtIndex:aTag];
//better to have #"spriteNameKey" defined in a macro somewhere: #define kAnimalResourceKeySprite #"SpriteKey"
self.sprite = [CCSprite spriteWithFile:[animalDict objectForKey:#"SpriteNameKey"]];
....
}
return self;
}
Phew! Then .. you guessed it!
-(void) showSecondLayer: (CCMenuItem*) sender
{
secondLayer = [SecondLayer layerWithAnimalResources:[AnimalResources animalResourcesWithTag:[sender tag]]];
secondLayer.position = ccp(0, 700);
[self addChild:secondLayer];
CCMoveTo *moveLayer = [CCMoveTo actionWithDuration:1.0 position:ccp(0, 0)];
[secondLayer runAction:moveLayer];
}
//Second Layer.h
+(id)layerWithAnimalResources:(AnimalResources*)resource;
-(id)initWithAnimalResources:(AnimalResources*)resource;
//Second Layer.m:
+(id)layerWithAnimalResources:(AnimalResources*)resource {
return [[[SecondLayer alloc] initWithAnimalResources:aTag] autorelease];
}
-(id) initWithAnimalResources:(AnimalResources*)resource
{
if( (self=[super init]))
{
//Change this sprite image based on button from main layer. I don't have it coded in yet, but I understand the concept of putting a variable in the file string using %# or %d
CCSprite *infoCard = [resource sprite];
infoCard.anchorPoint = ccp(0.5, 0);
infoCard.position = ccp(512, 0);
[self addChild:infoCard];
}
return self;
}
Give each menu item a unique id. In the method which you invoke on the tap of the button, you can reference the id of the sender. Use this id to populate the new layer with the unique information.
- (void) buttonPressed: (id) sender
{
MenuItem* item = (MenuItem*) sender;
int itemID = item.tag;
// Get unique data based on itemID and add new layer
}
EDIT: Per your code updates
-(void) showSecondLayer: (id) sender
{
CCMenuItemImage *item = (CCMenuItemImage *) sender;
int itemID = item.tag;
secondLayer = [SecondLayer node];
[secondLayer setItem: itemID]; // ADDED
secondLayer.position = CGPointMake(0, 700);
[self addChild:secondLayer];
CCMoveTo *moveLayer = [CCMoveTo actionWithDuration:1.0 position:CGPointMake(0, 0)];
[secondLayer runAction:moveLayer];
}
SecondLayer.m (the info layer)
-(id) init
{
if( (self=[super init]))
{
// Removed
}
return self;
}
-(void) setItem: (int) item
{
CCSprite *infoCard = [CCSprite spriteWithFile:[NSString stringWithFormat:#"species%d", item]];
infoCard.anchorPoint = CGPointMake(0.5, 0);
infoCard.position = CGPointMake(512, 0);
[self addChild:infoCard];
}

MKMapAnnotations didSelectAnnotationView not responding

I am creating an app that pulls data from a server and pinpoints the different houses on a map. My problem is that it does display the annotations but when I click on them they do not respond
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
I put my annotations in an array by:
int s;
self.mapAnnotations = [[NSMutableArray alloc] init];
for(s=0; s < numberOfAnnotations; s++)
{
//NSDictionary *dict2 = [parser objectWithString:[[arrayOfResults objectAtIndex:0] description]];
CLLocationDegrees daLong = [[[[[arrayOfResults objectAtIndex:s] objectForKey:#"map"] objectForKey:#"longitude"] description] floatValue];
CLLocationDegrees daLat = [[[[[arrayOfResults objectAtIndex:s] objectForKey:#"map"] objectForKey:#"latitude"] description] floatValue];
/*self.customAnnotation = [[BasicMapAnnotation alloc] initWithLatitude:daLat andLongitude:daLong];
[self.mapView addAnnotation:self.customAnnotation];*/
BasicMapAnnotation *m = [[BasicMapAnnotation alloc] initWithLatitude:daLat andLongitude:daLong];
[self.mapAnnotations addObject:m];
}
[self.mapView addAnnotations:self.mapAnnotations];
NSLog(#"this number of annotations %d", [self.mapAnnotations count]);
I also noticed when I created a separate house to place on the map in my viewDidLoad:
self.normalAnnotation = [[BasicMapAnnotation alloc] initWithLatitude:38 andLongitude:-90.2045];
self.normalAnnotation.title = #" ";
[self.mapView addAnnotation:self.normalAnnotation];
It did work when I clicked on it, but the ones passed through the array didn't work.
Can anyone help me figure out why it's not responding?
That's because annotations should have a title for them to display a callout. In your for loop, set the title property like you did with self.normalAnnotation.title = #" ".

Resources