Skip to content

Instantly share code, notes, and snippets.

@standinga
Created August 18, 2022 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save standinga/8879e1b6897d7cb9f865c7dd3915025f to your computer and use it in GitHub Desktop.
Save standinga/8879e1b6897d7cb9f865c7dd3915025f to your computer and use it in GitHub Desktop.
Swizzle UserDefaults set(object: forKey:) in objc and swift
/// ObjC
@implementation NSUserDefaults(Tracking)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(setObject:forKey:);
SEL swizzledSelector = @selector(swizzledSetObject:forKey:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
IMP originalImp = method_getImplementation(originalMethod);
IMP swizzledImp = method_getImplementation(swizzledMethod);
class_replaceMethod(class,
swizzledSelector,
originalImp,
method_getTypeEncoding(originalMethod));
class_replaceMethod(class,
originalSelector,
swizzledImp,
method_getTypeEncoding(swizzledSelector));
});
}
- (void) swizzledSetObject: (nullable id) object forKey: (nonnull NSString *) key {
[self swizzledSetObject:object forKey:key];
if ([key isEqualToString:@"trackedPropertyKey"]) {
NSLog(@"SwizzledSetObject %@ object: %@", key, object);
}
}
@end
// Swift
extension UserDefaults {
static let classInit: Void = {
let setObjectSelector = #selector(NSMutableDictionary.setObject(_:forKey:)) // or NSSelectorFromString("setObject:forKey:")
let setObjectMethod = class_getInstanceMethod(UserDefaults.self, setObjectSelector)
let setObjectSwizzledMethod = class_getInstanceMethod(UserDefaults.self, #selector(swizzleSet(_:forKey:)))
guard
let originalMethod = setObjectMethod,
let swizzledMethod = setObjectSwizzledMethod else
{
return
}
method_exchangeImplementations(originalMethod, swizzledMethod)
}()
@objc
func swizzleSet(_ value: Any?, forKey defaultName: String) {
swizzleSet(value, forKey: defaultName)
if
defaultName == "trackedPropertyKey" {
print("swizzleSet", defaultName, value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment