Question

I'm building an UITextView with text and images (Subclassing NSTextstorage for displaying my content)

I'm having textcontent with images URLs. So my problem is that i need download all the images if they're not cached.

So i want to first insert a placeholder image, download the image and then replace the placeholder image by the downloaded one.

Here's how i do my stuff.

First, i'm formatting my text with images url by replacing all urls with this tag :

[IMG]url[/IMG]

Then i'm using a regex to get all these tags.

I'm testing if there's a cached image or not. If not, i extract all the urls, download them and cache them.

I've created an NSObject class ImageCachingManager and declared a delegate method called when an image has been downloaded :

@protocol ImageCachingManagerDelegate <NSObject>

- (void)managerDidCacheImage:(UIImage *)image forUrl:(NSString *)url;

@end

Like this, I tough that I could use the url of the image got by the delegate method to search the matching url in my NSTextstorage attributedString and replace the current NSTextattachement image by the downloaded one.

But I don't know how to do that...

Thanks for help !

No correct solution

OTHER TIPS

I'm working on something very similar to this at the moment and think this might help. The code is very much alpha but hopefully it will get you to the next step - I'll step through:

Overall Cycle 1. Find you image tags in the full text piece using Reg Ex or XPath - personally i find Hppl to be more powerful but if your content is well structured and reliable, regex is probably fine.

https://github.com/topfunky/hpple

  1. Reduce the space of this match to 1 character and store that range - A textAttachment occupies only 1 character of space within a textview so it's best to reduce this to 1 otherwise when you replace your first match of characters in a range with the first textattachment the next range marker becomes out of date which will lead to issues. Depending on how much processing you need to do this text input during init, this is an important step, i have to do a lot of processing on the text and the ranges change during this parsing so I created an array of special characters that I know is never going to be in the inputs and push these single characters into the reserved space, at the same time i store this special character and the src of the image in an array of a very simple NSObject subclass that stores the SpecialChar, ImgSrc plus has space for the NSRange but i basically find the special character later in the process again because it has been moved about since this point and then set the nsrange at the very end of processing - this may not be necessary in your case but the principle is the same; You need a custom object with NsRange (which will become a text attachment) and the imgSource.

  2. Loop through this array to add placeholder imageAttachments to your attributed string. You can do this by adding a transparent image or a 'loading' image. You could also check your cache for existing images during this point and skipping the placeholder if it exists in cache.

  3. Using your delegate, when the image is successfully downloaded, you need to replace the current attachment with your new one. By replacing the placeholder in the range you've already stored in your object. Create a placeholder attributedString with the NSTextAttachment and then replace that range as below.

Some sample code:

Steps 1 & 2:

        specialCharsArray = [[NSArray alloc]initWithObjects:@"Û", @"±", @"¥", @"å", @"æ", @"Æ", @"Ç", @"Ø", @"õ", nil];

//using Hppl

NSString *allImagesXpathQueryString = @"//img/@src";
NSArray *imageArray = [bodyTextParser searchWithXPathQuery:allImagesXpathQueryString];
    //

    imageRanges = [[NSMutableArray alloc] init];

    if([imageArray count]){
        for (TFHppleElement *element in imageArray) {
            int i = 0;
            NSString *imgSource = [[[element children] objectAtIndex:0] content];

            NSString *replacementString = [specialCharsArray objectAtIndex:i];
            UIImage *srcUIImage = [UIImage imageNamed:imgSource];

            [srcUIImage setAccessibilityIdentifier:imgSource]; //only needed if you need to reference the image filename later as it's lost in a UIImage if stored directly

//imagePlacement is NSObject subclass to store the range, replacement and image as above

    imagePlacement *foundImage = [[imagePlacement alloc]init] ;


            [foundImage initWithSrc:srcUIImage replacement:replacementString];
            [imageRanges addObject:foundImage];
            i++;
        }

Step 3:

  -(void)insertImages{

    if ([imageRanges count]) {
        [self setScrollEnabled:NO]; //seems buggy with scrolling on
        int i = 0; //used to track the array placement for tag

        for(imagePlacement *myImagePlacement in imageRanges){

            // creates a text attachment with an image

            NSMutableAttributedString *placeholderAttString = [[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText];

            NSTextAttachment *attachment = [[NSTextAttachment alloc] init];

            //scales image down to ration of width of view - you probably don't need this
            CGSize scaleToView = imagePlacement.imgSrc.size;
            scaleToView.width = self.frame.size.width;
            scaleToView.height = (self.frame.size.width/imagePlacement.imgSrc.size.width)*imagePlacement.imgSrc.size.height;


            attachment.image = [self imageWithColor:[UIColor clearColor] andSize:scaleToView];
            NSMutableAttributedString *imageAttrString = [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];

            [self setAttributedText:placeholderAttString];

            i++;

        }
    }
    [self setScrollEnabled:YES];

}


- (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize) size {
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top