根据要求,这是我用来完成我需要完成的代码的代码。自从我查看这段代码以来已经有一年了,编写它更多的是为了了解正在发生的事情,而不是为了伟大的编码实践或任何形式的效率。然而,它确实奏效了,而且效果很好!
我定义了一个NSAttributedString类的代码如下。
示例使用:
-(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;
}
这是底层代码:
#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