Pertanyaan Cara sederhana untuk menyimpan NSMutableAttributedString di CoreData


Saya mencoba menyimpan NSMutableAttributedString di CoreData, tetapi saya mengalami masalah karena beberapa atribut saya NSMutableAttributedString berisi objek Core Foundation yang tidak dapat diarsipkan. Apakah ada cara mudah untuk menyimpan objek ini di CoreData tanpa harus melakukan beberapa hal yang berantakan secara manual?


5
2017-12-18 02:03


asal


Jawaban:


NSMutableAttributedString sesuai dengan NSCoding, yang berarti ia tahu bagaimana mengubah dirinya menjadi / dari NSData dan melakukannya melalui protokol yang Data Inti tahu cara menggunakannya.

Buat atribut "dapat diubah", dan kemudian tetapkan string yang dikaitkan dengannya. Karena dapat diubah, Core Data akan digunakan NSCoding untuk mengubahnya menjadi NSData saat Anda menetapkan nilai, dan mengubahnya kembali menjadi string yang dikaitkan saat Anda membacanya.

Catatan, Anda tidak akan dapat menggunakan predikat untuk memfilter hasil di bidang ini. Tetapi menyimpan dan mengambilnya sederhana.


5
2017-12-18 17:46



Sementara jawaban di atas benar, itu memiliki satu kerugian besar:

Tidak mungkin untuk membangun permintaan / predikat ambilan yang menanyakan konten objek NSAttributedString!

Predikat seperti ini akan menyebabkan pengecualian ketika dieksekusi:

[NSPredicate predicateWithFormat:@"(content CONTAINS[cd] %@)", @"test"]];

Untuk menyimpan 'NSAttributedString' dalam Data Inti diperlukan untuk menumpahkan NSAttributedString menjadi dua bagian: Sisi NSString (yang dapat diambil) dan sisi NSData, yang menyimpan atribut.

Perpecahan ini dapat dicapai dengan membuat tiga atribut dalam entitas Data Inti:

  1. atribut NSString bayangan ('contentString')
  2. atribut bayangan NSData ('contentAttributes')
  3. 'tidak ditentukan' sementara dikaitkan ('konten')

Dalam kelas entitas kustom, 'konten' mengaitkan yang dibuat dari bayangannya dan perubahan pada atribut juga dicerminkan ke bayangannya.

File header:

/**
 MMTopic
*/
@interface MMTopic : _MMTopic {}

@property (strong, nonatomic) NSAttributedString*   content;

@end

File implementasi:

/**
MMTopic (PrimitiveAccessors)

*/

@interface MMTopic (PrimitiveAccessors)

- (NSAttributedString *)primitiveContent;
- (void)setPrimitiveContent:(NSAttributedString *)pContent;

@end


/**
 MMTopic

 */
@implementation MMTopic    

static NSString const*  kAttributesDictionaryKey =  @"AttributesDictionary";
static NSString const*  kAttributesRangeKey =       @"AttributesRange";

/*
 awakeFromFetch

 */
- (void)awakeFromFetch {

    [super awakeFromFetch];

    // Build 'content' from its shadows 'contentString' and 'contentAttributes'
    NSString*                   string = self.contentString;
    NSMutableAttributedString*  content = [[NSMutableAttributedString alloc] initWithString:string];

    NSData*                     attributesData = self.contentAttributes;
    NSArray*                    attributesArray = nil;
    if (attributesData) {
        NSKeyedUnarchiver*  decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:attributesData];
        attributesArray = [[NSArray alloc] initWithCoder:decoder];
    }

    if ((content) &&
        (attributesArray.count)) {

        for (NSDictionary* attributesDictionary in attributesArray) {
            //NSLog(@"%@: %@", NSStringFromRange(((NSValue*)attributesDictionary[kAttributesRangeKey]).rangeValue), attributesDictionary[kAttributesDictionaryKey]);
            [content addAttributes:attributesDictionary[kAttributesDictionaryKey]
                             range:((NSValue*)attributesDictionary[kAttributesRangeKey]).rangeValue];
        }

        [self setPrimitiveContent:content];
    }
}

/*
 content

 */
@dynamic content;

/*
 content (getter)

 */
- (NSAttributedString *)content {

    [self willAccessValueForKey:@"content"];
    NSAttributedString* content = [self primitiveContent];
    [self didAccessValueForKey:@"content"];

    return content;
}

/*
 content (setter)

 */
- (void)setContent:(NSAttributedString *)pContent {

    [self willChangeValueForKey:@"content"];
    [self setPrimitiveValue:pContent forKey:@"content"];
    [self didChangeValueForKey:@"content"];

    // Update the shadows
    // contentString
    [self setValue:pContent.string
            forKey:@"contentString"];

    // contentAttributes
    NSMutableData*      data = [NSMutableData data];
    NSKeyedArchiver*    coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    NSMutableArray*     attributesArray = [NSMutableArray array];
    [pContent enumerateAttributesInRange:NSMakeRange(0, pContent.length)
                                 options:0
                              usingBlock:^(NSDictionary* pAttributesDictionary, NSRange pRange, BOOL* prStop) {
                                  //NSLog(@"%@: %@", NSStringFromRange(pRange), pAttributesDictionary);
                                  [attributesArray addObject:@{
                                                               kAttributesDictionaryKey:    pAttributesDictionary,
                                                               kAttributesRangeKey:     [NSValue valueWithRange:pRange],
                                                               }];
                              }];
    [attributesArray encodeWithCoder:coder];
    [coder finishEncoding];

    [self setValue:data
            forKey:@"contentAttributes"];
}

@end

Pengambilan sekarang dapat dilakukan dengan:

[NSPredicate predicateWithFormat:@"(contentString CONTAINS[cd] %@)", @"test"]];

Sementara akses ke NSAttributedString berjalan seperti ini:

textField.attributedText = pTopic.content;

Aturan untuk bekerja dengan 'atribut Non-Standar' dalam Data Inti didokumentasikan di sini: Dokumen Apple


4
2018-03-21 10:55



Yah saya tidak yakin apa yang Anda coba lakukan dengan string yang dikaitkan, tetapi jika itu diformat teks maka Anda tidak dapat menggunakan NSFont, dll.

Coba lihat di sini http://ossh.com.au/design-and-technology/software-development, Saya memposting beberapa hal tentang gaya dan gambar pemformatan dengan uitextview dan nstextview, tapi kebanyakan tentang string yang dikaitkan.

Barang-barang ini semuanya disimpan dalam data inti.


1
2017-12-19 22:47



Saya mulai menggunakan CoreText ketika iOS5 keluar, dan dengan demikian menggunakan nilai-nilai Core Foundation sebagai atribut. Namun saya sekarang menyadari bahwa sejak iOS6 keluar, saya sekarang dapat menggunakannya NSForegroundColorAttributeName, NSParagraphStyleAttributeName, NSFontAttributeName, dll. di kamus atribut, dan kunci-kunci tersebut disertai dengan objek seperti UIColor, NSMutableParagraphStyle, dan UIFont yang dapat diarsipkan.


1
2017-12-20 00:16