iOS - 当我将方法移到另一个类时,MKMapView的覆盖层不会渲染

3

我正在清理我的代码,以便在MKMapView苹果地图上渲染不同的覆盖层轨迹。

目前,当我使用两种方法-addOverlayTo:和mapView:rendererForOverlay-在我的视图控制器类"ParkMapVC"中时,我可以得到一个苹果地图,并且可以渲染出特定的叠加轨迹图像(在MKMapView对象上)。当我将这两种方法移动到另一个更通用的类“ParkMapOverlay” - 一个NSObject继承类中时,我可以直接执行我发送给它的“addOverlayTo:”方法,但无法使用mapView:rendererForOverlay方法。

在原始(正常工作)版本中,我没有直接发送mapView:rendererForOverlay消息,但是从跟踪调试器的结果来看,似乎是由我的addOverlayTo:方法触发的-我认为是由返回的对象触发的-虽然我并不完全清楚或确定。

这个可以工作:

    //  ParkMapVC.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "ParkMap.h"
#import "ParkMapVC.h"
@interface ParkMapVC : UIViewController <MKMapViewDelegate>{
}
@property (strong, nonatomic) IBOutlet MKMapView *hikeMap;
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (nonatomic, strong) ParkMap *park;
+ (ParkMapVC *) sharedParkMapVC;
- (void)addOverlayTo :(ParkMap*) thePark;
@end
#import "ParkMapVC.h"
#import "ParkMap.h"
#import "ParkMapOverlay.h"
#import "ParkMapOverlayView.h"
@interface ParkMapVC ()
@end
//*************
@implementation ParkMapVC
+ (ParkMapVC *) sharedParkMapVC {
    static ParkMapVC *sharedParkMapVC;
    @synchronized (self) {
        if (!sharedParkMapVC) {
            sharedParkMapVC = [[ParkMapVC alloc] init ];

        }
    return sharedParkMapVC;
    }

}
 - (void)viewDidLoad
{
    [super viewDidLoad];
    self.park = [[ParkMap alloc] initWithFilename:@"EdgewoodVer2"]; // plist
    // define region for apple map
     self.mapView.region = [self.park defineMapRegion:self.park];
    [self addOverlayTo:_park];
}
#pragma mark - Add methods
- (void)addOverlayTo :(ParkMap*) thePark{
    ParkMapOverlay *overlay = [[ParkMapOverlay alloc]          
                                       initWithPark:self.park];
    [self.mapView addOverlay:overlay];
}
#pragma mark - Map View delegate
// This should go to ParkMapOverlay 8.5.15
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {

        UIImage *overlayEdgewoodImage = [UIImage
            imageNamed:@"EDGEoverlay_park_Cropped"];

        ParkMapOverlayView *overlayView = [[ParkMapOverlayView alloc] initWithOverlay:overlay overlayImage:overlayEdgewoodImage];

        return overlayView;

  }

@end

不起作用的部分:

在这一点上,我将两个方法——addOverlayTo:和mapView:rendererForOverlay——移出到“ParkMapOverlay”类中。我改变了向 addOverlayTo 发送消息的方式,并且它确实从“ParkMapOverlay”类中执行了。然而,根据调试器断点,我可以看到 mapView:rendererForOverlay 方法未被调用,实际上覆盖层没有被渲染。我只能看到我的苹果地图显示在视图中。

这是代码: //在ParkMapVC中,我修改了覆盖层以向新类ParkMapOverlay发送消息

  [super viewDidLoad];
    self.park = [[ParkMap alloc] initWithFilename:@"EdgewoodVer2"]; 
    ParkMapOverlay *theOverlay = [[ParkMapOverlay alloc]init];

    self.mapView.region = [self.park defineMapRegion:self.park];
    self.mapView = [theOverlay addOverlayTo:_park ];

// Then I commented out the original two methods, moving the code to ParkMapOverlay 

//  ParkMapOverlay.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@class ParkMap;
@interface ParkMapOverlay : NSObject <MKOverlay, MKMapViewDelegate>
- (instancetype)initWithPark:(ParkMap *)park;
- (MKMapView *)addOverlayTo :(ParkMap*) thePark;
@end

//  ParkMapOverlay.m
#import "ParkMapOverlay.h"
#import "ParkMapOverlayView.h" 
#import "ParkMap.h"
@implementation ParkMapOverlay
@synthesize coordinate;
@synthesize boundingMapRect;
- (instancetype)initWithPark:(ParkMap *)park {
    self = [super init];
    if (self) {
        boundingMapRect = park.overlayBoundingMapRect;
        coordinate = park.midCoordinate;
    }

    return self;
}
- (MKMapView *)addOverlayTo :(ParkMap*) thePark
{
     ParkMapOverlay *overlay = [[ParkMapOverlay alloc]      initWithPark:thePark];
     MKMapView *mapView = [[MKMapView alloc] init];
    [mapView addOverlay:overlay];

    return mapView;

}
#pragma mark - Map View delegate


- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
           UIImage *overlayEdgewoodImage = [UIImage
                                      imageNamed:@"EDGEoverlay_park_Cropped"];

        ParkMapOverlayView *overlayView = [[ParkMapOverlayView alloc] initWithOverlay:overlay overlayImage:overlayEdgewoodImage];

        return overlayView;

    }
@end

我想了解以下几点:
  1. 这些方法最初是在ViewController类中的,现在它们在一个NSObject子类中
  2. 因为我不完全理解MKOverlayRenderer最初是如何被调用的,所以现在需要知道一些必须完成的触发条件
  3. 我现在在ParkMapVC的viewDidLoad方法中发送addOverlayTo:方法的方式似乎有问题
  4. 在Xamarin的“向地图添加覆盖物”示例中,我找到了一个引用,其中说“必须将OverlayRenderer方法分配给MkMapView之前才能添加MKOverlay”。我不确定这意味着什么——除非它与我在发送addOverlayTo:方法之前分配的ParkMapOverlay对象有关?
谢谢。 LRS
1个回答

1

mapView:rendererForOverlay:<MKMapViewDelegate>协议的一个方法。

在您的新的addOverlayTo:方法中,您正在初始化一个新的MKMapView对象,但没有将ParkMapOverlay对象设置为该地图视图的委托。这就是为什么mapView:rendererForOverlay:没有被调用的原因。

尝试像这样设置:mapView.delegate = self

还要注意内存管理:MKMapView的delegate是一个弱属性,即它不会保留其委托,因此您必须确保保留您的ParkMapOverlay对象。

当前应正确进行保留,因为您在一个类中同时具有覆盖功能和mapView:rendererForOverlay:方法,因此通过-[MKMapView addOverlay:]添加该类作为覆盖物可以确保对象被保留,但这是您设计的副作用,所以请注意。


谢谢Stanislaw。我正在努力想出如何融入你的想法。我认为也许我需要向addToOverlay方法添加另一个参数 - 传递我在ParkMapVC中实例化的MKMapView对象。 - LaurelS
哇!太棒了!它起作用了!我改变了我的方法,以便将原始的MKMapView对象作为(新的)第二个参数传递,称为“theMapView”。然后,在addOverlayTo:(等)方法中,我不再引用“mapView”,而是将所有这些对象更改为theMapView,我的路径叠加层再次显示在我的MKMapView对象之上。所以现在我可以构建所有的if this-then that trail逻辑,并根据很多事情开始显示不同的路径。- 你真的为我解决了难题,这里有一个英雄徽章吗?我也会勾选那个框。非常感谢您抽出时间阅读。 - LaurelS
-(MKMapView *)addOverlayTo:(ParkMap *)thePark withMapView:(MKMapView *)theMapView{ ParkMapOverlay *overlay = [[ParkMapOverlay alloc] initWithPark:thePark]; theMapView.delegate = self; [theMapView addOverlay:overlay]; return theMapView; } - LaurelS
似乎无法弄清楚将新代码版本粘贴到何处,以便未来遇到相同问题的人。我确实在每行开头放置了4个空白字符... - LaurelS
1
请在您的问题中进行更新,因为代码格式在评论中无法正常显示。 - Stanislav Pankevich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接