Skip to content

Instantly share code, notes, and snippets.

@kyle-ilantzis
Created December 2, 2019 17:05
Show Gist options
  • Save kyle-ilantzis/00f4685462a150506481a15ac2af7259 to your computer and use it in GitHub Desktop.
Save kyle-ilantzis/00f4685462a150506481a15ac2af7259 to your computer and use it in GitHub Desktop.
autofill SMS code webview crash https://openradar.appspot.com/7428013
func swizzleReplacingCharacters() {
let originalMethod = class_getInstanceMethod(
NSString.self, #selector(NSString.replacingCharacters(in:with:)))
let swizzledMethod = class_getInstanceMethod(
NSString.self, #selector(NSString.swizzledReplacingCharacters(in:with:)))
guard let original = originalMethod, let swizzled = swizzledMethod else {
return
}
method_exchangeImplementations(original, swizzled)
}
extension NSString {
@objc
func swizzledReplacingCharacters(in range: NSRange, with replacement: String) -> String {
/// By simply calling the original method the nil argument is handled. :shrug: :ok:
///
/// (yes, we will call the original method and not ourselves even though it looks like it,
/// because the methods have been swapped.)
return self.swizzledReplacingCharacters(in: range, with: replacement)
}
}
@zsj25502
Copy link

zsj25502 commented Dec 6, 2019

@zsj25502 you need to call swizzledReplacingCharacters from the AppDelegate if you want it to swap the two methods.

Hi, @Lorex7, thank you so much for the reply. I am pretty new to iOS development, and the existing project seems to be very complex, Would you be able to provide a more detail example on how to call this method in the AppDelegate.swift file, so that whenever the text is replacing it will trigger the new customized method? Thank you!!

@zsj25502
Copy link

zsj25502 commented Dec 6, 2019

@Lorex7 and Kyle, Thank you both so much!!! I managed to call it in the AppDelegate and everything looks perfect now!!!! Thanks again!

@yangloria
Copy link

Hi Kyle, thanks for sharing your method.
But i use Objective-C.. So Could you please let me know how to call that method in Objecitve-C?
i'm trying add "public"in front of function name but failed..
too difficult.TT

@kam800
Copy link

kam800 commented Jan 13, 2020

Does it mean, default ObjC implementation fails on empty tagged string, and Swift bridges empty tagged string to empty string? 😮
I once observed the same behavior in NSData. Nil NSData bridged to empty Data 🤣

@choi-bong-sik
Copy link

Hi Kyle, thanks for sharing your method.
But i use Objective-C.. So Could you please let me know how to call that method in Objecitve-C?
i'm trying add "public"in front of function name but failed..
too difficult.TT

did you have any solutions?

@623637646
Copy link

623637646 commented Jun 25, 2020

Here is Objective-c code. @yangloria @choi-bong-sik
This is from @acruis, Thanks

NSString+Swizzle.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSString (Swizzle)

@end

NS_ASSUME_NONNULL_END

NSString+Swizzle.m

#import "NSString+Swizzle.h"
#import <objc/runtime.h>

@implementation NSString (Swizzle)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(stringByReplacingCharactersInRange:withString:);
        SEL swizzledSelector = @selector(swizzle_stringByReplacingCharactersInRange:withString:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (success) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (NSString *)swizzle_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement
{
    return [self swizzle_stringByReplacingCharactersInRange:range withString:replacement ?: @""];
}

@end

@kyunkakata
Copy link

Here is Objective-c code. @yangloria @choi-bong-sik
This is from @acruis, Thanks

NSString+Swizzle.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSString (Swizzle)

@end

NS_ASSUME_NONNULL_END

NSString+Swizzle.m

#import "NSString+Swizzle.h"
#import <objc/runtime.h>

@implementation NSString (Swizzle)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(stringByReplacingCharactersInRange:withString:);
        SEL swizzledSelector = @selector(swizzle_stringByReplacingCharactersInRange:withString:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (success) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (NSString *)swizzle_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement
{
    return [self swizzle_stringByReplacingCharactersInRange:range withString:replacement ?: @""];
}

@end

Should I import "NSString+Swizzle.h" into AppDelegate.m and run load() function or it works without import anything.
If should import, please show me how to import it into AppDelegate.m
Please answer me @623637646, I stuck at this for the whole day, Thanks.

@623637646
Copy link

Should I import "NSString+Swizzle.h" into AppDelegate.m and run load() function or it works without import anything.
If should import, please show me how to import it into AppDelegate.m
Please answer me @623637646, I stuck at this for the whole day, Thanks.

Hi @kyunkakata , No need to import it. Just add those files to your project. The + (void)load will be called automatically.

@kyunkakata
Copy link

Should I import "NSString+Swizzle.h" into AppDelegate.m and run load() function or it works without import anything.
If should import, please show me how to import it into AppDelegate.m
Please answer me @623637646, I stuck at this for the whole day, Thanks.

Hi @kyunkakata , No need to import it. Just add those files to your project. The + (void)load will be called automatically.

Thank you @623637646

@seyoung-hyun
Copy link

@kyunkakata Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.

@kyunkakata
Copy link

That was @623637646 's code.

@623637646
Copy link

hi @seyoung-hyun . Feel free to use it. do remember to test before release to live.

@seyoung-hyun
Copy link

@kyunkakata Sorry for confusing you.
@623637646 Thanks your reply :)

hi @kyle-ilantzis.
I wonder if I use your code at this gist in my commercial app, too.
Please let me know how I can use the code for commercial distribution.
Thanks :)

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