19

iOS 11 adds smart quotes when typing. In macOS we can disable smart quotes on a NSTextView by setting:

textView.automaticQuoteSubstitutionEnabled = NO;  

Neither UITextField or UITextView seem to have this property or the enabledTextCheckingTypes property. How can smart quotes be disabled on iOS 11?

Kyle
  • 17,317
  • 32
  • 140
  • 246

3 Answers3

33

Smart quotes and other features such as smart dashes are controlled via the UITextInputTraits Protocol which is adopted by both UITextField and UITextView.

Specifically, the smartQuotesType property can be set to one of .default, .yes or .no. At this time there is no further documentation on these values, but .yes and .no are self-explanatory. My guess on .default is that the system will use properties such as textContentType and isSecureTextEntry to determine the appropriate behaviour.

For example a text content type of email, password or URL would probably disable smart quotes by default while job title may default to enabled. I imagine secure text entry fields would also have smarts disabled by default.

Setting an appropriate text content type for your input views can significantly improve the user experience and is highly recommended.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Nice addition. Just a clarification: `smartQuotesType` is only available in iOS11. [Apple docs](https://developer.apple.com/documentation/uikit/uitextinputtraits/2865931-smartquotestype) – Mr Spiegel Aug 25 '17 at 11:16
  • 1
    Well yes, but "iOS 11" are literally the first two words in the question title and the question, so I think that was pretty clear. – Paulw11 Aug 25 '17 at 11:17
  • That is right, but you might encounter this issue by running iOS10 apps in iOS11 devices. You might encounter **smart punctuation** issues in iOS11 that you could not get rid of unless your project is being compiled in iOS11. – Mr Spiegel Aug 25 '17 at 11:20
  • 5
    I would also add that it only prevents the smart quote from being entered from the keyboard. However, the user can type a smart quote from another app and copy/paste it into your `smartQuotesType = .no` text field. The best way to 'truly' prevent the smart quotes is to implement the delegate `textField:shouldChangeCharactersInRange:replacementString:` and detect a smart quote and replace it with a normal apostrophe. – micnguyen Oct 09 '17 at 10:52
  • @micnguyen how do you detect a smart quote? – Crashalot Dec 19 '17 at 03:32
  • 1
    @Crashalot You can check for these two characters: ‘ and ’. And then replace them with the ' character. – micnguyen Dec 19 '17 at 05:36
8

I don't think smartQuotesType and smartQuotesType are good practices for some languages.

Set these properties for every text inputs in our app:

if (@available(iOS 11.0, *)) {
    textView.smartDashesType = UITextSmartDashesTypeNo;
    textView.smartQuotesType = UITextSmartQuotesTypeNo;
    textView.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo;
} else {
    // Fallback on earlier versions
}

Creating a category to disable these "SMART" features makes no sense (bug):

- (UITextSmartDashesType)smartDashesType {
    return UITextSmartDashesTypeNo;
}
- (UITextSmartQuotesType)smartQuotesType {
    return UITextSmartQuotesTypeNo;
}
- (UITextSmartInsertDeleteType)smartInsertDeleteType {
    return UITextSmartInsertDeleteTypeNo;
}

So I tried to disable these features permanently by method swizzling:

#import <objc/runtime.h>

@implementation DisableFuckingSmartPunctuation

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

        SEL originalSelector = @selector(checkSmartPunctuationForWordInRange:);
        SEL swizzledSelector = @selector(checkSmartPunctuationForWordInRange:);

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

        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)checkSmartPunctuationForWordInRange:(id)arg1 {

}

@end

Hacking private methods always works like a charm...

i_82
  • 335
  • 5
  • 7
0

I had a problem with this - I frequently use Prompt and NX via my iPad Pro. Turning off "smart punctuation" in settings worked.

Tom
  • 9
  • 1