Actually there are 2 ways to implement the real "Hide Google tiles" method (johndope solution only puts an overlay on top of it but doesn't prevent the tiles from loading).
Beware that option one described below might get your application rejected while option 2 will not but is a bit more complex.
Common Part: Retrieve the MKMapTileView
object
Inside each MKMapView
lies an undocumented class of type: MKMapTileView
. Retrieving it is NOT a reason for rejection. In this code the MKMapView
instance will be called mapView
UIView* scrollview = [[[[mapView subviews] objectAtIndex:0] subviews] objectAtIndex:0];
UIView* mkTiles = [[scrollview subviews] objectAtIndex:0]; // <- MKMapTileView instance
Option 1: Undocumented Method (!! can be a reason for rejection !! )
if ( [mkTiles respondsToSelector:@selector(setDrawingEnabled:)])
[mkTiles performSelector:@selector(setDrawingEnabled:) withObject:(id)NO];
This will prevent the undocumented method setDrawingEnabled
to be called on the MKMapTileView
instance.
Option 2: Method Swizzling
Outside of your controller implementation you will write someting like:
// Import runtime.h to unleash the power of objective C
#import <objc/runtime.h>
// this will hold the old drawLayer:inContext: implementation
static void (*_origDrawLayerInContext)(id, SEL, CALayer*, CGContextRef);
// this will override the drawLayer:inContext: method
static void OverrideDrawLayerInContext(UIView *self, SEL _cmd, CALayer *layer, CGContextRef context)
{
// uncommenting this next line will still perform the old behavior
//_origDrawLayerInContext(self, _cmd, layer, context);
// change colors if needed so that you don't have a black background
layer.backgroundColor = RGB(35, 160, 211).CGColor;
CGContextSetRGBFillColor(context, 35/255.0f, 160/255.0f, 211/255.0f, 1.0f);
CGContextFillRect(context, layer.bounds);
}
And somewhere in your code (once your map view is loaded!) :
// Retrieve original method object
Method origMethod = class_getInstanceMethod([mkTiles class],
@selector(drawLayer:inContext:));
// from this method, retrieve its implementation (actual work done)
_origDrawLayerInContext = (void *)method_getImplementation(origMethod);
// override this method with the one you created
if(!class_addMethod([mkTiles class],
@selector(drawLayer:inContext:),
(IMP)OverrideDrawLayerInContext,
method_getTypeEncoding(origMethod)))
{
method_setImplementation(origMethod, (IMP)OverrideDrawLayerInContext);
}
Hope this helps anyone, this code was originally described in this blog post.