Regarding Apple's KMLViewer placemarkDescription and annotation subtitle

会有一股神秘感。 提交于 2019-12-20 04:23:14

问题


In my app I am using Apple's KMLViewer to show annotations that I get from a KML file.In the file KMLParser.m, there is an instance variable, placemarkDescription that converts the information under Description tags from kml file to annotation subtitle.Now, in my file every annotation has the information stored under Description in this way:

<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr><td><b>Fitness Bulls</b>---Palester sportive. Sporti dhe koha e lire.....<a href="http://www.site.com/BIZ_DIR/810180432/Article-Fitness-Bulls.aspx" style="color:Green;" >Shikoni detajet >></a></td></tr><tr><td><a href="http://www.site.com/HartaV2/AddReview.aspx?gisDataId=8123855e-b798-40bc-ad2e-00346a931211" style="color:Green;" >Shkruani pershtypjen tuaj >> </a> <p style="float:right;">Postuar nga:<i>Import</i></p></td></tr></table>

In KMLParser.m i have transformed the placemarkDescription from that to this:

<html><body>

<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr><td>     
<b>Fitness Bulls</b>---Palester sportive. Sporti dhe koha e lire.....
<a href="http://www.site.com/BIZ_DIR/810180432/Article-Fitness-Bulls.aspx"     style="color:Green;" >Shikoni detajet >></a></td></tr><tr><td>
<a href="http://www.site.com/HartaV2/AddReview.aspx?gisDataId=8123855e-b798-40bc-ad2e-00346a931211" style="color:Green;" >Shkruani pershtypjen tuaj >> </a> <p 

 style="float:right;">Postuar nga:<i>Import</i></p></td></tr></table>

 </body></html>

I've done this because I want to pas this string to a webView and visualize this in it. The problem is that when the kml loads, the methods get the description information, get called severe times.Exactly as times as placemarks stored in the kml.So passing the string directly has no effect.If i choose to set active the subtitle option (annotation.subtitle = placemarkDescription in KMLParser), maybe I gen get the subtitle info of the annotation the user tapped, but I don't want to show this information because it shows like this

<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr......

By the way, I don't have any idea of how to get the subtitle info of the selected annotation. So far, I have managed only to store the description information in an array (done this in the KMLParser.m).But what should I do with that array?How to know to which array entry corresponds the annotation the user tapped (the annotation that has the callout bubble opened).

So I don't know what to do. Maybe I have not been too clear: What I want to do is get the Description information of a placemark (annotation), when the user taps an annotation in the map, tapping the disclosureButton should redirect him to a webView that shows the description Information.

EDIT code Added:

DetailViewController.h

#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController<UIWebViewDelegate> {
UIWebView               *webView;
UITextField             *addressBar;
UIActivityIndicatorView *activityIndicator;
NSString                *placemarkDescription;
}

@property (nonatomic, retain) IBOutlet UIWebView                *webView;
@property (nonatomic, retain) IBOutlet UITextField              *addressBar;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView  *activityIndicator;
@property (nonatomic, retain) NSString                              *placemarkDescription;

-(IBAction) gotoAddress:(id)sender;
-(IBAction) goBack:(id)sender;
-(IBAction) goForward:(id)sender;

@end

DetailViewController.m

#import "DetailViewController.h"

@implementation DetailViewController

@synthesize webView, addressBar, activityIndicator, placemarkDescription;

- (void)viewDidLoad {
[super viewDidLoad];

[webView loadHTMLString:placemarkDescription baseURL:nil];

}

 -(IBAction)gotoAddress:(id) sender {
 NSURL *url = [NSURL URLWithString:[addressBar text]];
 NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

[webView loadRequest:requestObj];
[addressBar resignFirstResponder];
}

-(IBAction) goBack:(id)sender {
[webView goBack];
}

-(IBAction) goForward:(id)sender {
[webView goForward];
}

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request    navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
    NSURL *URL = [request URL]; 
    if ([[URL scheme] isEqualToString:@"http"]) {
        [addressBar setText:[URL absoluteString]];
        [self gotoAddress:nil];
    }    
    return NO;
}   
return YES;   
}

- (void)webViewDidStartLoad:(UIWebView *)webView {
[activityIndicator startAnimating];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; 
}

- (void)dealloc {
[super dealloc];
}

@end

PlacemarkAnnotation2.h

#import <Foundation/Foundation.h>
#import <MapKit/Mapkit.h>

@interface PlacemarkAnnotation2 : NSObject <MKAnnotation> {

CLLocationCoordinate2D coordinate;
NSString * title;
NSString * subtitle;
NSString * placemarkDescription;
}

@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * subtitle;
@property (nonatomic, retain) NSString * placemarkDescription;

@end

PlacemarkAnnotation2.m

#import "PlacemarkAnnotation2.h"

@implementation PlacemarkAnnotation2

@synthesize coordinate, title, subtitle, placemarkDescription;

- (id) initWithCoordinate:(CLLocationCoordinate2D)coord andTitle:(NSString *)maintitle andSubtitle:(NSString *)subTitle {
self.coordinate = coord;
self.title = maintitle;
self.subtitle = subTitle;

return self;
}

-(NSString *) placemarkDescription
{
return placemarkDescription;
}

- (void) setPlacemarkDescription: (NSString *) pd
{
placemarkDescription = pd;
}

- (void) dealloc {
[title dealloc];
[subtitle dealloc];
[placemarkDescription dealloc];

[super dealloc];
}

@end

Changes in KMLParser.M

//KMLPoint class

- (MKShape *)mapkitShape
{

PlacemarkAnnotation2 *annotation = [[PlacemarkAnnotation2 alloc] init];
annotation.coordinate = point;
return [annotation autorelease];
}

//KMLPlacemark class

- (void)_createShape
{
if (!mkShape) {
    mkShape = [[geometry mapkitShape] retain];
    mkShape.title = name;
    // Skip setting the subtitle for now because they're frequently
    // too verbose for viewing on in a callout in most kml files.

    NSString *lessThan = @"&lt;";
    NSString *greaterThan = @"&gt;";

    placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:lessThan
                                                                           withString:@"<"];
    placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:greaterThan
                                                                           withString:@">"];
    NSString *beforeBody = @"<html><body>";
    NSString *afterBody = @"</body></html>";

    NSString *finalContent = [[beforeBody stringByAppendingString:placemarkDescription] 
                                          stringByAppendingString:afterBody];                                 

    placemarkDescription = finalContent;

    mkShape.placemarkDescription = placemarkDescription;
}
}

Error found in this lines of code (No cause of crash description):

-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view 
calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(@">>> Entering %s <<<", __PRETTY_FUNCTION__);

DetailViewController *dvc = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:[NSBundle mainBundle]];
PlacemarkAnnotation2 *pa = (PlacemarkAnnotation2 *)view.annotation;
dvc.placemarkDescription = pa.placemarkDescription;
[self presentModalViewController:dvc animated:YES];
[dvc release];

NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}

回答1:


It's not clear how much of the KMLViewer sample app code you're using but one way to do this is to create your own annotation class instead of using the MKPointAnnotation class like the sample app does.

The custom class (eg. "PlacemarkAnnotation"), should implement the MKAnnotation protocol or be a sub-class of MKShape (if you are using the KMLViewer code). In the custom class, add a placemarkDescription property.

Where the KMLViewer code currently creates an MKPointAnnotation object, create a PlacemarkAnnotation instead and set its placemarkDescription property instead of the subtitle property.

Then in the viewForAnnotation delegate method, set the rightCalloutAccessoryView to a detail disclosure button.

Next, add to the project a detail view controller with a UIWebView in it. Add a placemarkDescription property to the view controller. In the viewDidLoad method, call loadHTMLString on the web view and pass it placemarkDescription (I think you can pass nil for the baseURL).

In the map view's calloutAccessoryControlTapped delegate method, create the detail view controller, set its placemarkDescription property and present it:

-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view 
    calloutAccessoryControlTapped:(UIControl *)control
{
    DetailViewController *dvc = [[DetailViewController alloc] init...
    PlacemarkAnnotation *pa = (PlacemarkAnnotation *)view.annotation;
    dvc.placemarkDescription = pa.placemarkDescription;
    [self presentModalViewController:dvc animated:YES];
    [dvc release];
}


Edit:

First, it looks like it will be best to subclass MKShape for your custom class instead of implementing the MKAnnotation protocol. The rest of the KMLViewer code is based on this assumption. So change @interface PlacemarkAnnotation2 : NSObject <MKAnnotation> to @interface PlacemarkAnnotation2 : MKShape. (By the way, for the NSString properties, copy is more appropriate than retain and it'll get rid of warnings.)

It also looks like you may have changed the type of the mkShape ivar in KMLPlacemark (and other places) from MKShape to something else. Change these types back to MKShape.

Next, _createShape might not be the best place to set the placemarkDescription since that method is called for both overlays and annotations. Remove your changes from that method and put them in the point method (also in KMLPlacemark). Note there are a couple of potential memory-related issues with your changes. Here's my suggestion:

- (void)_createShape
{
    if (!mkShape) {
        mkShape = [[geometry mapkitShape] retain];
        mkShape.title = name;
        // Skip setting the subtitle for now because they're frequently
        // too verbose for viewing on in a callout in most kml files.
    }
}

- (id <MKAnnotation>)point
{
    [self _createShape];

    if ([mkShape isKindOfClass:[PlacemarkAnnotation2 class]])
    {
        if (placemarkDescription != nil)
            //check for nil, otherwise will crash when 
            //passing to stringByAppendingString below
        {
            NSString *lessThan = @"&lt;";
            NSString *greaterThan = @"&gt;";

            placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:lessThan
                                                                                   withString:@"<"];
            placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:greaterThan
                                                                                   withString:@">"];
            NSString *beforeBody = @"<html><body>";
            NSString *afterBody = @"</body></html>";

            NSString *finalContent = [[beforeBody stringByAppendingString:placemarkDescription] 
                                      stringByAppendingString:afterBody];

            placemarkDescription = [finalContent retain];
                //added retain above since finalContent is autoreleased
                //and we are setting the ivar manually.  otherwise,
                //can result in EXC_BAD_ACCESS later.
        }

        PlacemarkAnnotation2 *pa2 = (PlacemarkAnnotation2 *)mkShape;
        pa2.placemarkDescription = placemarkDescription;

        return (id <MKAnnotation>)mkShape;
    }

    return nil;
}


来源:https://stackoverflow.com/questions/8285153/regarding-apples-kmlviewer-placemarkdescription-and-annotation-subtitle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!