Skip to content

Instantly share code, notes, and snippets.

@pita5
Created January 11, 2012 12:44
Show Gist options
  • Select an option

  • Save pita5/1594494 to your computer and use it in GitHub Desktop.

Select an option

Save pita5/1594494 to your computer and use it in GitHub Desktop.
// These classese should be treated as immutable
@interface MWAttributedString : NSObject <NSCoding>
- (id)initWithAttributedString:(NSAttributedString *)string;
- (NSAttributedString *)attributedString;
@end
@interface MWFont : NSObject <NSCoding>
- (id)initWithFont:(CTFontRef)font;
- (CTFontRef)fontRef;
@end
#import "MWAttributedString.h"
@interface MWAttributedString ()
@property (nonatomic, retain) NSAttributedString *attributedString;
@property (nonatomic, copy) NSString *string;
@property (nonatomic, retain) NSArray *attributes;
@end
@implementation MWAttributedString
@synthesize
string=_string,
attributes=_attributes,
attributedString=_attributedString;
- (id)initWithAttributedString:(NSAttributedString *)string
{
if ((self = [super init]))
{
__block BOOL error = NO;
NSMutableArray *attributes = [NSMutableArray array];
[string enumerateAttributesInRange:NSMakeRange(0, [string length])
options:0
usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stopAttrsInRange)
{
__block NSMutableDictionary *attributeDict = [NSMutableDictionary dictionary];
[attributeDict setObject:NSStringFromRange(range)
forKey:@"range"];
[attrs enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stopAttrs) {
if ([obj conformsToProtocol:@protocol(NSCoding)])
{
[attributeDict setObject:obj
forKey:key];
}
else
{
if ([key isEqualToString:@"CTForegroundColor"] ||
[key isEqualToString:@"CTStrokeColor"])
{
UIColor *color = [UIColor colorWithCGColor:(CGColorRef)obj];
[attributeDict setObject:color
forKey:key];
}
else if ([key isEqualToString:@"NSFont"])
{
CTFontRef font = (CTFontRef)obj;
if(!font)
{
error = YES; *stopAttrs = YES; *stopAttrsInRange = YES;
return;
}
[attributeDict setObject:[[[MWFont alloc] initWithFont:font] autorelease]
forKey:key];
}
else
{
// Something in here
NSLog(@"something %@", key);
}
}
[attributes addObject:attributeDict];
}];
}];
if (error)
{
[self release];
return nil;
}
[self setAttributes:attributes];
[self setString:[string string]];
[self setAttributedString:string];
}
return self;
}
- (void)dealloc
{
self.attributedString = nil;
self.attributes = nil;
self.string = nil;
[super dealloc];
}
- (NSAttributedString *)attributedString
{
if (!_string || !_attributes)
return nil;
if (_attributedString)
return _attributedString;
NSMutableAttributedString *str = [[[NSMutableAttributedString alloc] initWithString:_string] autorelease];
for (NSDictionary *dict in _attributes)
{
NSRange range = NSRangeFromString([dict objectForKey:@"range"]);
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (![key isEqualToString:@"range"])
[str addAttribute:key value:obj range:range];
}];
}
[self setAttributedString:str];
return str;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:_attributes
forKey:@"attributes"];
[coder encodeObject:_string
forKey:@"string"];
}
- (id)initWithCoder:(NSCoder *)coder
{
if ((self = [super init]))
{
[self setString:[coder decodeObjectForKey:@"string"]];
[self setAttributes:[coder decodeObjectForKey:@"attributes"]];
if (!_attributedString)
{
NSMutableArray *decodedAttributes = [NSMutableArray array];
for (NSDictionary *attr in _attributes)
{
NSMutableDictionary *copy = [attr mutableCopy];
if ([attr objectForKey:@"NSFont"])
{
MWFont *font = [attr objectForKey:@"NSFont"];
if (![font isKindOfClass:[MWFont class]])
continue;
[copy setObject:(id)[font fontRef]
forKey:@"NSFont"];
}
[decodedAttributes addObject:copy];
}
[self setAttributes:decodedAttributes];
}
}
return self;
}
@end
@interface MWFont ()
@property (nonatomic, retain) NSDictionary *attributes;
@property (nonatomic, assign) CTFontRef font;
@end
@implementation MWFont
@synthesize
attributes=_attributes,
font=_font;
- (void)dealloc
{
if (_font)
CFRelease(_font); _font = NULL;
self.attributes = nil;
[super dealloc];
}
- (id)initWithFont:(CTFontRef)font
{
if ((self = [super init]))
{
CTFontDescriptorRef descriptor = CTFontCopyFontDescriptor(font);
if (!descriptor)
{
[self release];
return nil;
}
CFDictionaryRef attrs = CTFontDescriptorCopyAttributes(descriptor);
[self setAttributes:[NSDictionary dictionaryWithDictionary:(NSDictionary *)attrs]];
CFRelease(attrs), attrs = NULL;
CFRelease(descriptor), descriptor = NULL;
_font = NULL;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if (_font) {
CFRelease(_font); _font = NULL;
}
[coder encodeObject:_attributes
forKey:@"attributes"];
}
- (id)initWithCoder:(NSCoder *)coder
{
if ((self = [super init]))
{
[self setAttributes:[coder decodeObjectForKey:@"attributes"]];
_font = NULL;
}
return self;
}
- (CTFontRef)fontRef
{
if (_font)
return _font;
CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)_attributes);
CTFontRef font = CTFontCreateWithFontDescriptor(fontDescriptor, [[_attributes objectForKey:@"NSFontSizeAttribute"] floatValue], NULL);
_font = font;
CFRelease(fontDescriptor), fontDescriptor = NULL;
return _font;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment