Super/subscripting in NSAttributedStrings

Has super/subscripting in NSAttributedStrings been deprecated in iPadOS 13? The Objective-C code line:


[attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@"1" range:NSMakeRange(k, range)];


works fine on my old iPad and simulators running iOS 12 and earlier, but is ignored on my iPad Pro and on simulators running any version of iPadOS 13. It isn't an Xcode 11 problem, since the same thing happens with my apps downloaded from the App Store several years ago.

Have you a small code example to test ?


I'm not fluent in objc, but are you sure you pass the right value with "1". Should be Int.

Isn't it without quotes ? as:

[attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:@1 range:NSMakeRange(k, range)];


There is no deprecation notice for kCTSuperscriptAttributeName in docuymentation.

It just states:


Discussion

Value must be a CFNumber object. Default is integer value

0
. If supported by the specified font, a value of
1
enables superscripting and a value of
-1
enables subscripting.


Did you check it is supported by the font you use ?

I tested your code on iPad simulator 13.4, with setting the attributed string to UILabel's attributedString, it worked as expected.


Can you show enough code to reproduce the same issue?


(The value should be @1, but @"1" worked the same as @1 .)

Thanks for the replies. They got me thinking. Here's what I've found so far:


First, with the exception of superscripting, all other attributes (font, size, font color, background color, underlining, etc.) that I've tried work fine in IPadOS 13, and everything (including superscripting) works fine in iOS 12 and earlier.


In iPadOS 13, the code snippet


attStr = [[NSMutableAttributedString alloc] initWithString:@"X2"];

[attStr addAttribute:(NSString*)kCTSuperscriptAttributeName value:@1 range:NSMakeRange(1, 1)];

aLabel.attributedText = attStr;


works fine for UILabels, but


attStr = [[NSMutableAttributedString alloc] initWithString:@"X2"];

[attStr addAttribute:(NSString*)kCTSuperscriptAttributeName value:@1 range:NSMakeRange(1, 1)];

[id setAttributedText: attStr];


doesn't work for UITextFields or UITextViews (I use the latter because I frequently need scrollers for app how-to info).


Interestingly, the developer documentation for NSAttributedStrings includes an NSAttributedStringKey named NSSuperscriptAttributeName, which you'd think would be good for superscripting. However, Xcode doesn'r recognize it, calling it an "undeclared identifier." Go figure.


I have a rather kluggy workaround that works for labels, textfields and textviews:


attStr = [[NSMutableAttributedString alloc] initWithString:@"X2"];

[attStr addAttribute:(NSString*)NSBaselineOffsetAttributeName value:@10 range:NSMakeRange(1, 1)];


where the value appears to be the text baseline offset in points, so it has to be fine-tuned for different font sizes (10 looks good for 15 pt system font). The superscript text size also has to be manually set.


Any ideas/comments would be appreciated.


-jim-

doesn't work for UITextFields or UITextView

I could have confirmed it did not work for UITextView, but worked for UITextField, in iPad simulator 13.4.


the developer documentation for NSAttributedStrings includes an NSAttributedStringKey named NSSuperscriptAttributeName

The constant NSSuperscriptAttributeName is only available in macOS, but I do not know why.

If Apple were planning to drop support for subscrip/superscript feature in iOS, it should not work for UILabel nor UITextField.


As far as tried, UITextView in iPad simulator can show attributedString made from HTML:

    NSString *htmlString = @"X<sup>2</sup>";
    attStr = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
               options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                         NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
    documentAttributes:nil error:nil];
    NSLog(@"%@(%@)", attStr, kCTSuperscriptAttributeName);
    self.textView.attributedText = attStr;

And `attStr` is shown as:

X{

NSColor = "kCGColorSpaceModelRGB 0 0 0 1 ";

NSFont = "<UICTFont: 0x7fa49b40b330> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 12.00pt";

NSKern = 0;

NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n), DefaultTabInterval 36, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";

NSStrokeColor = "kCGColorSpaceModelRGB 0 0 0 1 ";

NSStrokeWidth = 0;

}2{

NSColor = "kCGColorSpaceModelRGB 0 0 0 1 ";

NSFont = "<UICTFont: 0x7fa49b40c400> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 10.00pt";

NSKern = 0;

NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n), DefaultTabInterval 36, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";

NSStrokeColor = "kCGColorSpaceModelRGB 0 0 0 1 ";

NSStrokeWidth = 0;

NSSuperScript = 1;

}

You can find `NSSuperScript = 1;`, where `NSSuperScript` is a raw string and not symbolized.

I tried this:

    attStr = [[NSMutableAttributedString alloc] initWithString:@"X2"];
     [attStr addAttribute:@"NSSuperScript" value:@1 range:NSMakeRange(1, 1)];
    self.textView.attributedText = attStr;

And worked as expected.


As you know, using raw string for attribute names is not recommended and I do not know why constant symbol for NSSuperScript is not defined in iOS. But UITextView seems to have functionality to support superscript/subscript.


You should better send a bug report to Apple.

Using @"NSSuperscript" worked for me in UILabel, UITextField and UITextView, but only if I cut and pasted your addAttribute code line into my code. After pasting I could modify it to my needs. However, for some reason if I typed your line into my code, it wouldn't work -- maybe it sensed I was a doubter. Curious. It also worked with all iOS versions I tried (9,10, 12, & 13). I'm hesitant to call your answer the "Correct" answer, but it definitely works (as long as I copy/paste). Thanks much. Now I can get back to updating my apps before Apple pulls them.

Super/subscripting in NSAttributedStrings
 
 
Q