Skip to content

Instantly share code, notes, and snippets.

@ericallam
Created June 1, 2013 03:57
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericallam/5689235 to your computer and use it in GitHub Desktop.
Save ericallam/5689235 to your computer and use it in GitHub Desktop.
Mocking out CLLocationManager
#import <CoreLocation/CoreLocation.h>
extern CLLocationDegrees kMockedLatitude;
extern CLLocationDegrees kMockedLongitude;
@interface CLLocationManager (MockingLocation)
+ (BOOL)custom_locationServicesEnabled;
+ (CLAuthorizationStatus)custom_authorizationStatus;
-(void)custom_startUpdatingLocation;
-(CLLocation *)custom_location;
@end
#import "CLLocationManager+MockingLocation.h"
// The lat and long of the mocked current location
CLLocationDegrees kMockedLatitude = 28.5388;
CLLocationDegrees kMockedLongitude = -81.3756;
// This category implements methods that will be swizzled to replace key methods
// in CLLocationManager to mock out the user location
@implementation CLLocationManager (MockingLocation)
// replaces locationServicesEnabled;
+ (BOOL)custom_locationServicesEnabled;
{
return YES;
}
// replaces startUpdatingLocation, will send the locationManager:didUpdateLocations: message
// to the delegate after a wait of 0.1 seconds using dispatch_after to simulate how
// startUpdatingLocation actually works. This will not simulate any kind of location errors
-(void)custom_startUpdatingLocation;
{
CLLocation *usersCurrentLocation = [[CLLocation alloc] initWithLatitude:kMockedLatitude longitude:kMockedLongitude];
if (self.delegate) {
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
// Send the locationManager:didUpdateLocations: message to location manager after 0.1 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSArray *locations = @[usersCurrentLocation];
[self.delegate locationManager:self didUpdateLocations:locations];
});
}
}
}
// replaces location, returns the mocked CLLocation object, does not current
// have any support for mocking altitude or anything other than lat/long
-(CLLocation *)custom_location;
{
return [[CLLocation alloc] initWithLatitude:kMockedLatitude longitude:kMockedLongitude];
}
@end
#import <Foundation/Foundation.h>
@interface CSSwizzler : NSObject
+(void)swizzleClass:(id)cls
replaceClassMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
+(void)swizzleClass:(id)cls
replaceMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
+(void)swizzleClassOfInstance:(id)inst
replaceMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
@end
#import "CSSwizzler.h"
#import <objc/message.h>
#import <objc/runtime.h>
@implementation CSSwizzler
+(void)swizzleClass:(id)cls
replaceClassMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
{
Method origMethod = nil, altMethod = nil;
origMethod = class_getClassMethod(cls, origMethodSelector);
altMethod = class_getClassMethod(cls, replacementMethodSelector);
method_exchangeImplementations(origMethod, altMethod);
}
+(void)swizzleClass:(id)cls
replaceMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
{
Method origMethod = nil, altMethod = nil;
origMethod = class_getInstanceMethod(cls, origMethodSelector);
altMethod = class_getInstanceMethod(cls, replacementMethodSelector);
method_exchangeImplementations(origMethod, altMethod);
}
+(void)swizzleClassOfInstance:(id)inst
replaceMethod:(SEL)origMethodSelector
withMethod:(SEL)replacementMethodSelector;
{
const char *str = [[[inst class] description] UTF8String];
Class cls = objc_getClass(str);
Method origMethod = nil, altMethod = nil;
origMethod = class_getInstanceMethod(cls, origMethodSelector);
altMethod = class_getInstanceMethod(cls, replacementMethodSelector);
method_exchangeImplementations(origMethod, altMethod);
}
@end
#import "LocationMocker.h"
#import "CSSwizzler.h"
#import "CLLocationManager+MockingLocation.h"
@implementation LocationMocker
// This method gets automatically called as soon as this class
// is loaded
+(void) load;
{
// locationServicesEnabled exists as both a class method
[CSSwizzler swizzleClass:[CLLocationManager class]
replaceClassMethod:@selector(locationServicesEnabled)
withMethod:@selector(custom_locationServicesEnabled)];
// and an instance method on CLLocationManager, thus we will swizzle it
// twice
[CSSwizzler swizzleClass:[CLLocationManager class]
replaceMethod:@selector(locationServicesEnabled)
withMethod:@selector(custom_locationServicesEnabled)];
[CSSwizzler swizzleClass:[CLLocationManager class]
replaceMethod:@selector(startUpdatingLocation)
withMethod:@selector(custom_startUpdatingLocation)];
[CSSwizzler swizzleClass:[CLLocationManager class]
replaceMethod:@selector(location)
withMethod:@selector(custom_location)];
}
@end
@rrallo
Copy link

rrallo commented Aug 1, 2013

Is there a LocationMocker.h file missing? I see you import it in the LocationMocker.m

@iliaskarim
Copy link

Hey @rallo, there is no need for a header as it is not imported anyhow.

@iliaskarim
Copy link

You would add the following somewhere either in the .m or .h

@interface LocationMocker: NSObject

@end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment