7

I created a subclass of NSMutableAttributedString in one of my projects to make a string that continually changes each character to one of the colors given in an array on init, but when I try to call the init method, I get a sigabrt on the initWithString: method.

RainbowString.h

#import <Foundation/Foundation.h>

@interface RainbowString : NSMutableAttributedString

@property (nonatomic) NSArray* colors;
@property (nonatomic) NSTimeInterval duration;
@property (nonatomic) NSTimer* timer;

- (id)initStringWithColors:(NSArray*)colors withString:(NSString*)string;
- (id)initStringWithColors:(NSArray*)colors withCycleDuration:(NSTimeInterval)duration withString:(NSString*)string;

- (void)stop;
- (void)start:(NSTimeInterval)duration;

@end 

initWithColors:

- (id)initStringWithColors:(NSArray *)colors withString:(NSString *)string
{
    self = [super initWithString:string];
    if(self)
    {
        [self setColors:colors];
        [self cycle];
    }

    return self;
}

Even if I just call [[RainbowString alloc] initWithString:@"Hello"];, I get the same error:

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RainbowString initWithString:]: unrecognized selector sent to instance 0x166778c0'

Update

Okay, so just to test this, I created a test subclass of NSMutableAttributedString with absolutely no content. I just created the subclass and left it plain.

Test.h

#import <Foundation/Foundation.h>

@interface Test : NSMutableAttributedString

@end

I ran:

[[NSMutableAttributedString alloc] initWithString:@"Hello"];

That ran and compiled fine. But then I ran:

[[Test alloc] initWithString:@"Hello"];

Same error. Am I not allowed to subclass NSMutableAttributedString or something?

Liftoff
  • 24,717
  • 13
  • 66
  • 119

2 Answers2

7

Your conclusion is correct. NS(Mutable)AttributedString is a class cluster, and subclassing those doesn't work. Pity the Apple documentation doesn't clearly identify it as one.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • So how could I go about accomplishing what I had in mind? It's basically an attributed string where every letter is a different color (given an array of UIColors) and they all change every .1 seconds? – Liftoff Feb 11 '14 at 03:15
  • @David - A common approach: design a class which *has a*, as opposed to *is a*, `NS(Mutable)AttributedString`. Indeed if you read the `NSAttributedString` documentation it states that it itself is a wrapper, rather than a subclass, of `NSString`. – CRD Feb 11 '14 at 03:19
  • So would I be creating a *new* NSMAS every time the timer fires, or could I just edit the one? – Liftoff Feb 11 '14 at 03:21
  • @David - Strange question. Your design, your choice. Or maybe I'm misunderstanding what you're asking? – CRD Feb 11 '14 at 04:32
0

For future searchers, this gist may be handy. It's a sub-class of NSAttributedString that re-implements the public interface of NSAttributedString via composition - calls to the public methods are passed through to an internal instance of NSAttributedString.

I wouldn't use it for production code, but sometimes it's a useful starting point when you want to temporarily instrument aspects of NSAttributedString during development.

user2067021
  • 4,399
  • 37
  • 44