【问题标题】:Regarding Apple's KMLViewer placemarkDescription and annotation subtitle关于苹果的KMLViewer placemarkDescription 和annotation subtitle
【发布时间】:2011-11-27 11:17:52
【问题描述】:

在我的应用程序中,我使用 Apple 的 KMLViewer 显示从 KML 文件中获取的注释。在文件 KMLParser.m 中,有一个实例变量 placemarkDescription 将描述标签下的信息从 kml 文件转换为注释subtitle.Now,在我的文件中,每个注释都以这种方式存储在描述下的信息:

<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>

在 KMLParser.m 中,我将 placemarkDescription 从那个转换为这个:

<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>

我这样做是因为我想将此字符串传递给 webView 并在其中可视化它。 问题是,当 kml 加载时,方法获取描述信息,被称为严重时间。与存储在 kml 中的地标的时间完全一样。所以直接传递字符串没有效果。如果我选​​择设置激活字幕选项( annotation.subtitle = placemarkDescription 在 KMLParser 中),也许我会获取用户点击的注释的字幕信息,但我不想显示此信息,因为它显示如下

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

顺便说一句,我不知道如何获取所选注释的字幕信息。 到目前为止,我只设法将描述信息存储在一个数组中(在 KMLParser.m 中完成)。但是我应该如何处理该数组?如何知道哪个数组条目对应于用户点击的注释(注释标注气泡已打开)。

所以我不知道该怎么办。 可能我还不太清楚:我想做的是获取地标(注解)的Description信息,当用户点击地图中的注解时,点击disclosureButton应该会将他重定向到显示描述信息的webView。

编辑代码添加:

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

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;
}
}

在这行代码中发现错误(无崩溃原因描述):

-(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__);
}

【问题讨论】:

    标签: iphone ios annotations mkmapview kml


    【解决方案1】:

    尚不清楚您使用了多少 KMLViewer 示例应用程序代码,但一种方法是创建您自己的注释类,而不是像示例应用程序那样使用 MKPointAnnotation 类。

    自定义类(例如“PlacemarkAnnotation”)应该实现MKAnnotation 协议或者是MKShape 的子类(如果您使用的是KMLViewer 代码)。在自定义类中,添加 placemarkDescription 属性。

    如果 KMLViewer 代码当前创建 MKPointAnnotation 对象,则创建 PlacemarkAnnotation 并设置其 placemarkDescription 属性而不是 subtitle 属性。

    然后在viewForAnnotation 委托方法中,将rightCalloutAccessoryView 设置为详细信息披露按钮。

    接下来,向项目中添加一个带有UIWebView 的详细视图控制器。将placemarkDescription 属性添加到视图控制器。在viewDidLoad方法中,在web视图上调用loadHTMLString并传递placemarkDescription(我认为你可以传递nilbaseURL)。

    在地图视图的calloutAccessoryControlTapped委托方法中,创建详细视图控制器,设置其placemarkDescription属性并呈现:

    -(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];
    }
    


    编辑:

    首先,看起来最好为您的自定义类继承MKShape,而不是实现MKAnnotation 协议。 KMLViewer 代码的其余部分基于此假设。所以将@interface PlacemarkAnnotation2 : NSObject &lt;MKAnnotation&gt; 更改为@interface PlacemarkAnnotation2 : MKShape。 (顺便说一句,对于NSString 属性,copyretain 更合适,它会消除警告。)

    看起来您可能已将KMLPlacemark(和其他地方)中的mkShape ivar 的类型从MKShape 更改为其他类型。将这些类型改回MKShape

    接下来,_createShape 可能不是设置placemarkDescription 的最佳位置,因为覆盖和注释都会调用该方法。从该方法中删除您的更改并将它们放入point 方法中(也在KMLPlacemark 中)。请注意,您的更改存在一些与内存相关的潜在问题。这是我的建议:

    - (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;
    }
    

    【讨论】:

    • 好的,完成所有事情。我将 MKShape 子类化,但现在给出错误 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MKPointAnnotation setPlacemarkDescription:]: unrecognized selector sent to instance 0xb819910'。我还测试了MKAnnotationprotocl 的实现,但由于错误没有构建,它找不到 MKShape 的 setPlacemarkDescription 属性。
    • 请重新阅读答案中的前两段。您需要将 placemarkDescription 属性添加到自定义类并更改 KMLViewer 中创建 MKPointAnnotation 的代码并改为创建自定义类。
    • 其实是第二段和第三段(不是前两段)。
    • 我做到了。我确实向自定义类添加了 placemarkDescription 属性并更改了 KMLViewer 中的代码,它在其中创建 MKPointAnnotation 并创建了自定义类,但它向我显示了有关 mkShape 的 setPlacemarkDescription 属性的错误. 调用 DetailView 时应用也会崩溃。
    • 您是否为该属性添加了@synthesize?请发布您所做的所有更改和添加。还要给出崩溃位置和确切的崩溃消息。
    猜你喜欢
    • 2012-01-24
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多