Split NSAttributedString into Image + NSString

1.5k views Asked by At

I have an NSAttributedString that can contain 3 different things :

  • Just an image. (an attachment)
  • Just Text
  • An image followed by text (/!\ not the other way around, never).

I'm trying to "scan" that object to know if I have an image or text, and if there is an image, if there is text afterwards.

I'm not comfortable with using the enumeration and range parameters ; the documentation didn't really help me understand how to make this work.

How would you achieve this ?

  • Extract image if there is one
  • Extract string if there is one (either alone or after the image).

The only code I have now is from another SO post that was kind of helpful if there was only an image.

 NSAttributedString *currentString = self.inputToolbar.contentView.textView.attributedText;
 __block UIImage *currentImage = nil;    
    [currentString enumerateAttribute:NSAttachmentAttributeName
                                 inRange:NSMakeRange(0, [currentString length])
                                 options:0
                              usingBlock:^(id value, NSRange range, BOOL *stop)
                              {
                                  if ([value isKindOfClass:[NSTextAttachment class]])
                                  {
                                      NSTextAttachment *attachment = (NSTextAttachment *)value;
                                      UIImage *image = nil;
                                      if ([attachment image])
                                          image = [attachment image];
                                      else
                                          image = [attachment imageForBounds:[attachment bounds]
                                                               textContainer:nil
                                                              characterIndex:range.location];

                                      if (image)
                                          currentImage = image;
                                  }
                              }];
1

There are 1 answers

3
Larme On

The idea is to keep the same logic, but using a NSMutableAttributedString instead of a NSAttributedString, keep the NSRange of the image, and delete it.

NSMutableAttributedString *currentString = [[NSMutableAttributedString alloc] initWithAttributedString:self.inputToolbar.contentView.textView.attributedText];
__block UIImage *currentImage = nil;    
__block NSRange imageRange;
[currentString enumerateAttribute:NSAttachmentAttributeName
                                 inRange:NSMakeRange(0, [currentString length])
                                 options:0
                              usingBlock:^(id value, NSRange range, BOOL *stop)
                              {
                                  if ([value isKindOfClass:[NSTextAttachment class]])
                                  {
                                      NSTextAttachment *attachment = (NSTextAttachment *)value;
                                      UIImage *image = nil;
                                      if ([attachment image])
                                          image = [attachment image];
                                      else
                                          image = [attachment imageForBounds:[attachment bounds]
                                                               textContainer:nil
                                                              characterIndex:range.location];

                                      if (image)
                                      {
                                          currentImage = image;
                                          imageRange = range;
                                      }
                                  }
                              }];

NSString *text = @"";
if (image)
{
    text = [[currentString deleteCharactersInRange:imageRange] string];
}

if ([text length] > 0)
{
    NSLog(@"Found Text: %@", text);
}
else
{
    NSLog(@"Did Found Text");
}


NSLog(image?@"Found Image";@"Did NOT found image");