简体   繁体   中英

iOS - MKMapView Overlay won't render when I move methods to another class

Working on cleaning up my code so I can render different overlays of trails atop an MKMapView apple map, depending...

Currently I have an apple map coming up and I can get a specific overlay trail image rendered (over an MKMapView object) when I use two methods -addOverlayTo: and mapView:rendererForOverlay - within my view controller class "ParkMapVC". When I move those two methods to another more generic class "ParkMapOverlay" - an NSObject inheriting class, I can get the "addOverlayTo:" method I message directly to execute, but not the mapView:rendererForOverlay method.

I didn't directly message mapView:rendererForOverlay in the original (working) version, but from following the debugger, it seemed it was triggered by my addOverlayTo: method - I think by the object returned - though I'm not entirely clear or sure about that.

This works:

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

What does not work :

At this point - I moved the two methods - addOverlayTo: and mapView:rendererForOverlay- out to the class "ParkMapOverlay". I changed the way I was messaging addOverlayTo and it does execute from within the "ParkMapOverlay" class. However, based on debugger breakpoints, I can see that the mapView:rendererForOverlay method is not messaged , and indeed the overlay is not rendered. I just see my apple map displayed in the view.

Here is the code: //Within ParkMapVC I altered overlay to message the new class 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

What I wonder about -

  1. The methods were originally in a ViewController class, now they are in a class that is an NSObject child
  2. Because I don't entirely understand how the MKOverlayRenderer is invoked originally, there is something I need to know about that has to be done to trigger that now
  3. Something about the way I now message the addOverlayTo: method in my viewDidLoad method in ParkMapVC is tripping me up
  4. I found a reference in Xamarin in the "Add an Overlay to a Map" recipe, that says "The OverlayRenderer method must be assigned to prior to adding the MKOverlay to the MkMapView". I'm not sure what this means - unless it has to do with the object that ParkMapOverlay object I alloc init before I message the addOverlayTo: method ?

Thank you. LRS

mapView:rendererForOverlay: is a method of <MKMapViewDelegate> protocol.

In your new addOverlayTo: method you are initializing new MKMapView object but are not setting your ParkMapOverlay object as that map view's delegate. This is why mapView:rendererForOverlay: is not called.

Try to set it like mapView.delegate = self .

Also be careful with memory management: MKMapView's delegate is a weak property ie it does not retain its delegate so you must be sure to keep your ParkMapOverlay object retained.

Currently retain should happen correctly because you have both overlay functionality and mapView:rendererForOverlay: method in one class so that adding that class as overlay via -[MKMapView addOverlay:] ensures that object is retained but that is a side-effect of your design so be aware of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM