Cocoa: How to save NSAttributedString to JSON

前端 未结 3 971
梦毁少年i
梦毁少年i 2021-02-10 06:44

I have a NSAttributedString object as a property of a custom object. I need to save this custom object to the disk in JSON format. Later I need to

相关标签:
3条回答
  • 2021-02-10 07:15

    You could try starting with RTFFromRange:

    From the documentation: For information about the OS X methods supporting RTF, ..., see NSAttributedString Application Kit Additions Reference.

    RTF should be self contained. RTFFromRange: returns NSData; I would think its probably character data in some encoding so should be easy to convert to NSString.

    (Sorry, just read that method is MacOS X only).

    0 讨论(0)
  • 2021-02-10 07:17

    NSAttributedString has two properties:

    • the string
    • an array of attribute "runs"

    Each "run" has:

    • an integer range that it applies to
    • a dictionary of key/value attributes

    It would be very easy to represent that as JSON, using enumerateAttributesInRange:options:usingBlock:.

    Something like:

    {
      "string" : "Hello World",
      "runs" : [
        {
          "range" : [0,3],
          "attributes" : {
            "font" : {
              "name" : "Arial",
              "size" : 12
            }
          }
        },
        {
          "range" : [3,6],
          "attributes" : {
            "font" : {
              "name" : "Arial",
              "size" : 12
            },
            "color" : [255,0,0]
          }
        },
        {
          "range" : [9,2],
          "attributes" : {
            "font" : {
              "name" : "Arial",
              "size" : 12
            }
          }
        }
      ]
    }
    

    EDIT: here's an example implementation:

    // create a basic attributed string
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:@"Hello World" attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Arial" size:12]}];
    [attStr addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(3, 6)];
    
    // build array of attribute runs
    NSMutableArray *attributeRuns = [NSMutableArray array];
    [attStr enumerateAttributesInRange:NSMakeRange(0, attStr.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
      NSArray *rangeArray = @[[NSNumber numberWithUnsignedInteger:range.location],
                              [NSNumber numberWithUnsignedInteger:range.length]];
    
      NSMutableDictionary *runAttributes = [NSMutableDictionary dictionary];
      [attrs enumerateKeysAndObjectsUsingBlock:^(id attributeName, id attributeValue, BOOL *stop) {
    
        if ([attributeName isEqual:NSFontAttributeName]) { // convert font values into a dictionary with the name and size
          attributeName = @"font";
          attributeValue = @{@"name": [(NSFont *)attributeValue displayName],
                             @"size": [NSNumber numberWithFloat:[(NSFont *)attributeValue pointSize]]};
    
        } else if ([attributeName isEqualToString:NSForegroundColorAttributeName]) { // convert foreground colour values into an array with red/green/blue as a number from 0 to 255
          attributeName = @"color";
          attributeValue = @[[NSNumber numberWithInteger:([(NSColor *)attributeValue redComponent] * 255)],
                             [NSNumber numberWithInteger:([(NSColor *)attributeValue greenComponent] * 255)],
                             [NSNumber numberWithInteger:([(NSColor *)attributeValue blueComponent] * 255)]];
    
        } else { // skip unknown attributes
          NSLog(@"skipping unknown attribute %@", attributeName);
          return;
        }
    
    
        [runAttributes setObject:attributeValue forKey:attributeName];
      }];
    
      // save the attributes (if there are any)
      if (runAttributes.count == 0)
        return;
    
      [attributeRuns addObject:@{@"range": rangeArray,
                                 @"attributes": runAttributes}];
    }];
    
    // build JSON output
    NSDictionary *jsonOutput = @{@"string": attStr.string,
                                 @"runs": attributeRuns};
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonOutput options:NSJSONWritingPrettyPrinted error:NULL];
    
    NSLog(@"%@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
    exit(0);
    
    0 讨论(0)
  • 2021-02-10 07:25

    You could use this simple code snippet to convert NSAttributedString to XML without actually parsing NSAttributedString. This can be a human-readable alternative to JSON if you can afford verbose text output.

    It can be also used for decoding back to NSAttributedString.

        let data = NSMutableData()
    
        let archiver = NSKeyedArchiver(forWritingWithMutableData: data)
        archiver.outputFormat = .XMLFormat_v1_0
        textView.attributedText.encodeWithCoder(archiver)
        archiver.finishEncoding()
    
        let textAsString = NSString(data: data, encoding: NSUTF8StringEncoding)'
    
    0 讨论(0)
提交回复
热议问题