Skip to content

Repository files navigation

NSAttributedString Build Status

It's not a secret that NSAttributedString API is far from perfect. Based on NSDictionary, it looks ugly, counter-OOP and hard to maintain...

NSMutableAttributedString *attributedString = [[NSMutableAttributedStringalloc] initWithString:@"Test attributed string"attributes:@{NSForegroundColorAttributeName: [UIColor greenColor], NSFontAttributeName: [fnt fontWithSize:20]}];
[attributedString addAttributes:@{NSForegroundColorAttributeName: [UIColor redColor]
, NSFontAttributeName: [fnt2 fontWithSize:10]
, NSLigatureAttributeName: @2
, NSBaselineOffsetAttributeName: @1}
range:NSMakeRange(3, 5)];
[attributedString addAttributes:@{NSForegroundColorAttributeName: [UIColor blueColor]
, NSFontAttributeName: [fnt2 fontWithSize:30]}
range:NSMakeRange(6, 9)];
[attributedString addAttributes:@{NSStrikethroughStyleAttributeName: @(NSUnderlineStyleSingle)
, NSStrikethroughColorAttributeName: [UIColor redColor]
, NSBackgroundColorAttributeName: [UIColor yellowColor]}
range:NSMakeRange(7, 4)];
_attributedTextView2.attributedText = attributedString;

Some developers get really desperate and write tools like this... Which again proves that NSAttributedString API is far from perfect.

Masonry

I love masonry. I love its clarity, its syntax. If you are using autolayout in your project and still write constraints using NSLayoutConstraint API, you should definitely take a look at masonry. Clear and very brief syntax makes code much more human readable, easy to maintain and modify.

BOString

So, based on masonry syntax, I decided to create a similar framework, which will take away some pain of creating NSAttributedString:

NSMutableAttributedString *attributedString = [@"Test attributed string"bos_makeString:^(BOStringMaker *make) {
make.foregroundColor([UIColor greenColor]);
make.font([fnt fontWithSize:20]);
make.with.range(NSMakeRange(3, 5), ^{
make.foregroundColor([UIColor redColor]);
make.font([fnt2 fontWithSize:10]);
make.ligature(@2);
make.baselineOffset(@1);
});
make.with.range(NSMakeRange(6, 9), ^{
make.foregroundColor([UIColor blueColor]);
make.font([fnt2 fontWithSize:30]);
});
make.with.range(NSMakeRange(7, 4), ^{
make.strikethroughStyle(@(NSUnderlineStyleSingle));
make.strikethroughColor([UIColor redColor]);
make.backgroundColor([UIColor yellowColor]);
});
}];

While making a string you can specify ranges for attributes either with a block-based syntax as in the example above:

make.with.range(NSMakeRange(6, 9), ^{
make.foregroundColor([UIColor blueColor]);
make.font([fnt2 fontWithSize:30]);
});

or set range for a specific attribute (with is an optional semantic filler):

make.foregroundColor([UIColor blueColor]).with.range(NSRange(6, 9));
make.font([fnt2 fontWithSize:30]).range(NSRange(6, 9));

If you don't specify range, full range of string will be used.

Which attributes BOString supports? It supports a lot of them:

font;
paragraphStyle;
foregroundColor;
backgroundColor;
ligature;
kern;
strikethroughStyle;
underlineStyle;
strokeColor;
strokeWidth;
shadow;
textEffect; // iOS only
attachment;
link;
baselineOffset;
underlineColor;
strikethroughColor;
obliqueness;
expansion;
writingDirection;
verticalGlyphForm;
superscript; // OS X only
cursor; // OS X only
toolTip; // OS X only
characterShape; // OS X only
glyphInfo; // OS X only
markedClauseSegment; // OS X only
textAlternatives; // OS X only

"Wait, you forgot NSTheVeryBestAndUsefulAttribute!"

Indeed, there are many CoreText attributes that are not defined as methods. I.e. kCTLanguageAttributeName, kCTCharacterShapeAttributeName, kCTBaselineClassAttributeName, etc. In this case you may use attribute method:

make.attribute(kCTLanguageAttributeName, @"jp");

Even more than just an NSAttributedString maker!

A couple of substring attribute setters. Set attributes for a first substring found:

NSAttributedString *result = [@"This is a string"bos_makeString:^(BOStringMaker *make) {
make.first.substring(@"is", ^{
make.foregroundColor([UIColor greenColor]);
});
}];

or highlight every substring:

NSAttributedString *result = [@"This is a string"bos_makeString:^(BOStringMaker *make) {
make.each.substring(@"is", ^{
make.foregroundColor([UIColor greenColor]);
});
}];

You can also apply attributes using regular expressions:

NSAttributedString *result = [@"This is a string"bos_makeString:^(BOStringMaker *make) {
make.each.regexpMatch(@"\\ws", NSRegularExpressionCaseInsensitive, ^{
make.foregroundColor([UIColor greenColor]);
});
}];

Or regular expressions with groups matching:

NSAttributedString *result = [@"This is a string"bos_makeString:^(BOStringMaker *make) {
make.first.regexpGroup(@"[^h](i\\w)\\s(\\w*)", NSRegularExpressionCaseInsensitive, ^{
make.foregroundColor([UIColor greenColor]);
});
}];

Shorthand

In order to avoid conflicts with any other frameworks, bos_ prefix is used for category methods. However shorthand methods without this prefix could be used if you add #define BOS_SHORTHAND in your prefix.pch file before importing BOString.h.

Documentation

Documentation in HTML is available here or on cocoadocs.org.

Supported platforms

  • iOS 6.0 and later.
  • OS X Mavericks (10.9) and later.

Should work fine on iOS 4.3+ and OS X 10.5+ (except of several attributes), but I haven't had a chance to test it.

Installation

The easiest way is to use CocoaPods:

In your Podfile

pod 'BOString'

and import it in a file you want to make strings like a boss:

#import "Bostring.h"

Contribution

Feel free to submit pull requests into a separate branch. Please don't submit pull requests to master.

License

BOString is released under the MIT License.

About

Create NSAttributedString like a boss!

Topics

Resources

Stars

191 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages