Search code examples
iosswiftnsmutableattributedstring

Applying NSMutalbeAtrributedString crashes


I have a UIButton and I'm trying to set the title to have 2 lines and the second line should be a smaller font than the first. Here's my code:

self.startBtn.setTitle("First\nSecond Line", forState: .Normal)

let string = NSMutableAttributedString()
string.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(13), range: NSMakeRange(4, 5))
self.startBtn.titleLabel?.attributedText = string

When I run the app, I get the following error:

Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000106fbbc65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000106c54bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x0000000106fbbb9d +[NSException raise:format:] + 205
    3   Foundation                          0x00000001067e26ae -[NSRLEArray objectAtIndex:effectiveRange:] + 142
    4   Foundation                          0x00000001067fa029 -[NSConcreteMutableAttributedString addAttribute:value:range:] + 209
    5   myApp                             0x00000001064e0a93 _TFC7myApp18MainViewController9startTimefS0_FCSo8UIButtonT_ + 1363
    6   myApp                             0x00000001064e0eaa _TToFC7myApp18MainViewController9startTimefS0_FCSo8UIButtonT_ + 58
    7   UIKit                               0x0000000107561da2 -[UIApplication sendAction:to:from:forEvent:] + 75
    8   UIKit                               0x000000010767354a -[UIControl _sendActionsForEvents:withEvent:] + 467
    9   UIKit                               0x0000000107672919 -[UIControl touchesEnded:withEvent:] + 522
    10  UIKit                               0x00000001075ae998 -[UIWindow _sendTouchesForEvent:] + 735
    11  UIKit                               0x00000001075af2c2 -[UIWindow sendEvent:] + 682
    12  UIKit                               0x0000000107575581 -[UIApplication sendEvent:] + 246
    13  UIKit                               0x0000000107582d1c _UIApplicationHandleEventFromQueueEvent + 18265
    14  UIKit                               0x000000010755d5dc _UIApplicationHandleEventQueue + 2066
    15  CoreFoundation                      0x0000000106eef431 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    16  CoreFoundation                      0x0000000106ee52fd __CFRunLoopDoSources0 + 269
    17  CoreFoundation                      0x0000000106ee4934 __CFRunLoopRun + 868
    18  CoreFoundation                      0x0000000106ee4366 CFRunLoopRunSpecific + 470
    19  GraphicsServices                    0x00000001096cca3e GSEventRunModal + 161
    20  UIKit                               0x0000000107560900 UIApplicationMain + 1282
    21  myApp                             0x00000001064da2c7 main + 135
    22  libdyld.dylib                       0x0000000109ab3145 start + 1
    23  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Solution

  • The reason you get the exception is that your NSMutableAttributedString is empty at the time when you set the font for some of its characters. Making sure that the string has characters in the range {4, 5} will fix this problem:

    let string = NSMutableAttributedString(string:"First\nSecond Line")
    string.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(13), range: NSMakeRange(4, 5))
    self.startBtn.titleLabel?.attributedText = string
    

    Note: Characters in the range {4, 5} are "t\nSec". If you wand the second line to be in smaller font, the range should be {6, 11}.