10

NSTextViewで選択したテキストにカスタム属性を追加する必要があります。したがって、選択範囲の属性付き文字列を取得し、それにカスタム属性を追加してから、選択範囲を新しい属性付き文字列に置き換えることで、これを行うことができます。

これで、テキストビューの属性付き文字列をNSDataとして取得し、ファイルに書き込みます。後でそのファイルを開いてテキストビューに復元すると、カスタム属性がなくなります。カスタム属性のスキーム全体を検討した後、カスタム属性が保存されていないことがわかりました。ここで重要な注意事項を見てください:http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/AttributedStrings/Tasks/RTFAndAttrStrings.html

したがって、このカスタム属性を使用してドキュメントを保存および復元する方法がわかりません。何か助けはありますか?

4

2 に答える 2

17

を保存する通常の方法はNSAttributedStringRTFを使用することであり、RTFデータが生成される-dataFromRange:documentAttributes:error:方法です。NSAttributedString

ただし、RTF形式はカスタム属性をサポートしていません。代わりに、NSCodingプロトコルを使用して属性付き文字列をアーカイブする必要があります。これにより、カスタム属性が保持されます。

//asssume attributedString is your NSAttributedString
//encode the string as NSData
NSData* stringData = [NSKeyedArchiver archivedDataWithRootObject:attributedString];
[stringData writeToFile:pathToFile atomically:YES];

//read the data back in and decode the string
NSData* newStringData = [NSData dataWithContentsOfFile:pathToFile];
NSAttributedString* newString = [NSKeyedUnarchiver unarchiveObjectWithData:newStringData];
于 2010-04-13T03:01:25.370 に答える
6

Cocoaを使用してカスタム属性をRTFに保存する方法があります。これは、RTFがテキスト形式であるという事実に依存しているため、RTFのすべての規則を知らなくても、カスタムRTFリーダー/ライターがなくても、文字列として操作できます。以下に概説する手順は、書き込みと読み取りの両方でRTFを後処理し、私はこの手法を個人的に使用しました。非常に注意すべき点の1つは、RTFに挿入するテキストは7ビットASCIIのみを使用し、「\{}」を含むエスケープされていない制御文字を使用しないことです。

データをエンコードする方法は次のとおりです。

NSData *GetRtfFromAttributedString(NSAttributedString *text)
{
    NSData *rtfData = nil;
    NSMutableString *rtfString = nil;
    NSString *customData = nil, *encodedData = nil;
    NSRange range;
    NSUInteger dataLocation;

// Convert the attributed string to RTF
    if ((rtfData = [text RTFFromRange:NSMakeRange(0, [text length]) documentAttributes:nil]) == nil)
        return(nil);

// Find and encode your custom attributes here. In this example the data is a string and there's at most one of them
    if ((customData = [text attribute:@"MyCustomData" atIndex:0 effectiveRange:&range]) == nil)
        return(rtfData); // No custom data, return RTF as is
    dataLocation = range.location;

// Get a string representation of the RTF
    rtfString = [[NSMutableString alloc] initWithData:rtfData encoding:NSASCIIStringEncoding];

// Find the anchor where we'll put our data, namely just before the first paragraph property reset
    range = [rtfString rangeOfString:@"\\pard" options:NSLiteralSearch];
    if (range.location == NSNotFound)
        {
        NSLog(@"Custom data dropped; RTF has no paragraph properties");
        [rtfString release];
        return(rtfData);
        }

// Insert the starred group containing the custom data and its location
    encodedData = [NSString stringWithFormat:@"{\\*\\my_custom_keyword %d,%@}\n", dataLocation, customData];
    [rtfString insertString:encodedData atIndex:range.location];

// Convert the amended RTF back to a data object    
    rtfData = [rtfString dataUsingEncoding:NSASCIIStringEncoding];
    [rtfString release];
    return(rtfData);
}

この手法が機能するのは、準拠しているすべてのRTFリーダーが、キーワードが認識されない「スター付きグループ」を無視するためです。したがって、コントロールワードが他のリーダーに認識されないようにする必要があるため、会社名や製品名のプレフィックスなど、一意である可能性が高いものを使用してください。データが複雑またはバイナリである場合、またはエスケープしたくない不正なRTF文字が含まれている可能性がある場合は、base64でエンコードしてください。キーワードの後に​​必ずスペースを入れてください。

同様に、RTFを読み取るときは、制御ワードを検索し、データを抽出して、属性を復元します。このルーチンは、属性付き文字列とそれが作成されたRTFを引数として取ります。

void RestoreCustomAttributes(NSMutableAttributedString *text, NSData *rtfData)
{
    NSString *rtfString = [[NSString alloc] initWithData:rtfData encoding:NSASCIIStringEncoding];
    NSArray *components = nil;
    NSRange range, endRange;

// Find the custom data and its end
    range = [rtfString rangeOfString:@"{\\*\\my_custom_keyword " options:NSLiteralSearch];
    if (range.location == NSNotFound)
        {
        [rtfString release];
        return;
        }
    range.location += range.length;

    endRange = [rtfString rangeOfString:@"}" options:NSLiteralSearch
        range:NSMakeRange(range.location, [rtfString length] - endRange.location)];
    if (endRange.location == NSNotFound)
        {
        [rtfString release];
        return;
        }

// Get the location and the string data, which are separated by a comma
    range.length = endRange.location - range.location;
    components = [[rtfString substringWithRange:range] componentsSeparatedByString:@","];
    [rtfString release];

// Assign the custom data back to the attributed string. You should do range checking here (omitted for clarity)
    [text addAttribute:@"MyCustomData" value:[components objectAtIndex:1]
        range:NSMakeRange([[components objectAtIndex:0] integerValue], 1)];
}
于 2011-05-25T16:16:17.533 に答える