2013-12-18 14 views
5

Próbuję przechowywać NSMutableAttributedString w CoreData, ale mam problemy, ponieważ niektóre z atrybutów moich NSMutableAttributedString zawierają obiekty Core Foundation, których nie można zarchiwizować. Czy istnieje prosty sposób, aby ten obiekt był przechowywany w CoreData bez konieczności ręcznego robienia bałaganu?Prosty sposób na przechowywanie NSMutableAttributedString w CoreData

+0

Jak proponujecie przechowywania rzeczy, które nie mogą być archiwizowane? –

+0

@DuncanGroenewald - O to pytam, zgadnij, że to niemożliwe? –

+0

Jakie są konkretne rzeczy, które zawarłeś we właściwościach? Nie możesz ich podklasować i dodać archiwizacji do własnej podklasy. –

Odpowiedz

1

Zacząłem używać CoreText, gdy system iOS5 był niedostępny, a tym samym używał wartości Core Foundation jako atrybutów. Jednak teraz zdaję sobie sprawę, że odkąd wyszedł iOS6, mogę teraz używać w słowniku atrybutów: NSForegroundColorAttributeName, itd. Do klawiszy tych dołączone są takie obiekty, jak UIColor, NSMutableParagraphStyle i UIFont, które można archiwizować.

5

NSMutableAttributedString jest zgodny z NSCoding, co oznacza, że ​​wie, jak przekonwertować się na/z NSData i robi to za pośrednictwem protokołu, który Core Data wie, jak używać.

Utwórz atrybut "przekształcalny", a następnie po prostu przypisz do niego przypisane łańcuchy. Ponieważ jest to przekształcalne, Core Data użyje NSCoding, aby przekonwertować go na NSData po przypisaniu wartości i przekonwertować ją z powrotem na przypisany ciąg, gdy go przeczytasz.

Uwaga: nie można użyć predykatu do filtrowania wyników w tym polu. Ale przechowywanie i pobieranie jest proste.

+0

Jest zgodny z NSCoding, ale możliwe, że jego właściwości nie będą (atrybuty). –

1

Więc nie jestem pewien, co chce zrobić z przypisywanego ciąg, ale jeśli jest to tekst sformatowany wtedy nie można użyć NSFont, etc ..

Spójrz tutaj http://ossh.com.au/design-and-technology/software-development, napisałem parę rzeczy na temat formatowania stylów i obrazów za pomocą uitextview i nstextview, ale w większości chodzi o przypisane ciągi.

Wszystko to jest przechowywane w danych podstawowych.

4

Chociaż powyższa odpowiedź jest dobra, to ma jedną wielką wadę:

nie jest możliwe zbudowanie pobrać wniosek/predykat że kwerendy zawartości obiektu NSAttributedString!

Predykat tak spowoduje wyjątek, kiedy wykonywane: jest to potrzebne

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

aby przechowywać „fetchable” NSAttributedString w podstawowych danych do rozlał NSAttributedString na dwie części: po stronie NSString (który może być pobrane) i stronę NSData, która przechowuje atrybuty.

Podział ten może być osiągnięty poprzez utworzenie trzech atrybutów jednostki DANE PODSTAWOWE:

  1. atrybut cień NSString („contentString”)
  2. cień NSData atrybutu („contentAttributes”)
  3. 'undefined' transient attributed ('content')

W niestandardowej klasie encji "treść" przypisana do utworzonej z cienia i zmiany do atrybutu są również lustrem jego cienie.

plik nagłówka: plik

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

@property (strong, nonatomic) NSAttributedString* content; 

@end 

Realizacja:

/** 
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 

Pobieranie mogą być teraz wykonywane przez:

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

Chociaż każdy dostęp do NSAttributedString idzie tak:

textField.attributedText = pTopic.content; 

Zasady pracy z „atrybutów Non-standard” w danych Core są udokumentowane tutaj: Apple docs