As requested, here's the code I used to accomplish what i needed to accomplish. It's been a year since I looked at this code, and it was written more to understand what was going on than for great coding practices or for any sort of efficiency. However, it did work, and it worked great!
I defined a category of NSAttributedString code is below.
Example use:
-(void)code:(id)sender {
self.testData=[textView.attributedString customEncode];
NSLog(@"%@",self.testData);
}
-(void)recover:(id)sender {
NSAttributedString* tString=[NSMutableAttributedString customDecode:self.testData];
NSLog(@"Recover pressed: %@",tString);
textView.attributedString=tString;
}
And here's the underlying code:
#import "NSAttributedString+Extras.h"
#import <CoreText/CoreText.h>
@implementation NSAttributedString (Extras)
-(NSData*)customEncode {
__block NSMutableArray* archivableAttributes=[[NSMutableArray alloc]init];
[self enumerateAttributesInRange:NSMakeRange(0, [self length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(@"range: %d %d",range.location, range.length);
NSLog(@"dict: %@",attrs);
NSLog(@"keys: %@", [attrs allKeys]);
NSLog(@"values: %@", [attrs allValues]);
NSMutableDictionary* tDict=[[NSMutableDictionary alloc]init];
[tDict setObject:[NSNumber numberWithInt:range.location] forKey:@"location"];
[tDict setObject:[NSNumber numberWithInt:range.length] forKey:@"length"];
for (NSString* tKey in [attrs allKeys]) {
if ([tKey isEqualToString:@"CTUnderlineColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:@"CTUnderlineColor"])] forKey:@"CTUnderlineColor"];
}
if ([tKey isEqualToString:@"NSUnderline"]) {
NSNumber* underline=[attrs objectForKey:@"NSUnderline"];
[tDict setObject:underline forKey:@"NSUnderline"];
}
if ([tKey isEqualToString:@"CTForegroundColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:@"CTForegroundColor"])] forKey:@"CTForegroundColor"];
}
if ([tKey isEqualToString:@"NSFont"]) {
CTFontRef font=((CTFontRef)[attrs objectForKey:@"NSFont"]);
NSDictionary* fontDict=[NSDictionary
dictionaryWithObjects:
[NSArray arrayWithObjects:(NSString*)CTFontCopyPostScriptName(font),[NSNumber numberWithFloat:CTFontGetSize(font)], nil]
forKeys:
[NSArray arrayWithObjects:@"fontName", @"fontSize", nil]];
[tDict setObject:fontDict forKey:@"NSFont"];
}
}
[archivableAttributes addObject:tDict];
}];
NSMutableDictionary* archiveNSMString=[NSMutableDictionary
dictionaryWithObjects: [NSArray arrayWithObjects:[self string],archivableAttributes,nil]
forKeys:[NSArray arrayWithObjects:@"string",@"attributes",nil]];
NSLog(@"archivableAttributes array: %@",archiveNSMString);
NSData* tData=[NSKeyedArchiver archivedDataWithRootObject:archiveNSMString];
NSLog(@"tdata: %@",tData);
return tData;
}
+(NSAttributedString*)customDecode:(NSData *)data {
NSMutableAttributedString* tString;
NSMutableDictionary* tDict=[NSKeyedUnarchiver unarchiveObjectWithData:data];
NSArray* attrs;
CTFontRef font=NULL;
CGColorRef color=NULL;
NSNumber* underlineProp=[NSNumber numberWithInt:0];
CGColorRef underlineColor=NULL;
NSLog(@"decoded dictionary: %@",tDict);
if ([[tDict allKeys]containsObject:@"string"]) {
tString=[[NSMutableAttributedString alloc]initWithString:((NSString*)[tDict objectForKey:@"string"])];
}
else {
tString=[[NSMutableAttributedString alloc]initWithString:@""];
}
if ([[tDict allKeys]containsObject:@"attributes"]) {
attrs=[tDict objectForKey:@"attributes"];
}
else {
attrs=nil;
}
for (NSDictionary* attDict in attrs) {
int location=-1;
int length=-1;
NSRange insertRange=NSMakeRange(-1, 0);
if ([[attDict allKeys]containsObject:@"location"]) {
location=[[attDict objectForKey:@"location"]intValue];
}
if ([[attDict allKeys]containsObject:@"length"]) {
length=[[attDict objectForKey:@"length"]intValue];
}
if (location!=-1&&length!=-1) {
insertRange=NSMakeRange(location, length);
}
if ([[attDict allKeys]containsObject:@"NSUnderline"]) {
underlineProp=[attDict objectForKey:@"NSUnderline"];
}
if ([[attDict allKeys]containsObject:@"CTUnderlineColor"]) {
underlineColor=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:@"CTUnderlineColor"]];
}
if ([[attDict allKeys]containsObject:@"CTForegroundColor"]) {
color=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:@"CTForegroundColor"]];
}
if ([[attDict allKeys]containsObject:@"NSFont"]) {
NSString* name=nil;
float size=-1;
NSDictionary* fontDict=[attDict objectForKey:@"NSFont"];
if ([[fontDict allKeys]containsObject:@"fontName"]) {
name=[fontDict objectForKey:@"fontName"];
}
if ([[fontDict allKeys]containsObject:@"fontSize"]) {
size=[[fontDict objectForKey:@"fontSize"]floatValue];
}
if (name!=nil&&size!=-1) {
font=CTFontCreateWithName((CFStringRef)name, size, NULL);
}
}
if (insertRange.location!=-1) {
if (color!=NULL) {
[tString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)color range:insertRange];
}
if (font!=NULL) {
[tString addAttribute:(NSString*)kCTFontAttributeName value:(id)font range:insertRange];
}
if ([underlineProp intValue]!=0&&underlineColor!=NULL) {
[tString addAttribute:(NSString*)kCTUnderlineColorAttributeName value:(id)underlineColor range:insertRange];
[tString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:(id)underlineProp range:insertRange];
}
}
}
[tString enumerateAttributesInRange:NSMakeRange(0, [tString length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(@"range: %d %d",range.location, range.length);
NSLog(@"dict: %@",attrs);
NSLog(@"keys: %@", [attrs allKeys]);
NSLog(@"values: %@", [attrs allValues]);
}];
return [[NSAttributedString alloc]initWithAttributedString:tString];
}
+(NSArray*)arrayFromCGColorComponents:(CGColorRef)color {
int numComponents=CGColorGetNumberOfComponents(color);
CGFloat* components=CGColorGetComponents(color);
NSMutableArray* retval=[[NSMutableArray alloc]init];
for(int i=0;i<numComponents;i++) {
[retval addObject:[NSNumber numberWithFloat:components[i]]];
}
return [NSArray arrayWithArray:retval];
}
+(CGColorRef)cgColorRefFromArray:(NSArray*)theArray {
CGFloat* array=malloc(sizeof(CGFloat)*[theArray count]);
for (int i=0; i<[theArray count]; i++) {
array[i]=[[theArray objectAtIndex:i]floatValue];
}
CGColorSpaceRef theSpace;
if ([theArray count]==2) {
theSpace=CGColorSpaceCreateDeviceGray();
}
else {
theSpace=CGColorSpaceCreateDeviceRGB();
}
return CGColorCreate(theSpace, array);
}
@end