NSCoding Persisting UIImage In NerdFeed


#1

I have added thumbnails to the NerdFeed app but it does not persist the image when i use NSCoding methods. Other that that it is persisting everything including title, labels etc.

[code]- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:title forKey:@“title”];
[aCoder encodeObject:link forKey:@“link”];
[aCoder encodeObject:creator forKey:@“creator”];
[aCoder encodeObject:pubDate forKey:@“pubDate”];
[aCoder encodeObject:thumbnail forKey:@“thumbnail”];
}

  • (id)initWithCoder:(NSCoder *)aDecoder
    {
    self = [super init];
    if (self)
    {
    [self setTitle:[aDecoder decodeObjectForKey:@“title”]];
    [self setLink:[aDecoder decodeObjectForKey:@“link”]];
    [self setCreator:[aDecoder decodeObjectForKey:@“creator”]];
    [self setPubDate:[aDecoder decodeObjectForKey:@“pubDate”]];
    [self setThumbnail:[aDecoder decodeObjectForKey:@“thumbnail”]];
    }
    return self;
    }[/code]

Do i need to do something extra for persisting the images in NerdFeed app? Thanks


#2

Unrelated but good practice tip.

Consider using identifiers for constants that you use elsewhere, to avoid errors caused by typos.

For example:

...
// Names for our archiving keys
static NSString *const myArkKeyTitle = @"title";
static NSString *const myArkKeyLink  = @"link";
...
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:title forKey:myArkKeyTitle];
    [aCoder encodeObject:link forKey:myArkKeyLink];
    ...
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self)
    {
        [self setTitle:[aDecoder decodeObjectForKey:myArkKeyTitle]];
        [self setLink:[aDecoder decodeObjectForKey:myArkKeyLink]];
        ...
     }
    return self;
}

#3

As you said your answer is Unrelated. I would really appreciate if someone can guide me why images are not getting saved while other items are persisting properly.

Thanks


#4

Have you tried logging out the value of thumbnail in both these methods and seeing what it is during runtime?


#5

Its NULL. I guess the problem is not in the encode and decode methods. It might be where i am calling them. Or may be fetchRSSFeedWithCompletion method is not enough to handle images. While titles and other labels are persisting correctly.


#6

Any help would be much appreciated… :confused:


#7

Its NULL. I guess the problem is not in the encode and decode methods. It might be where i am calling them. Or may be fetchRSSFeedWithCompletion method is not enough to handle images. While titles and other labels are persisting correctly.[/quote]
Joe has given you the clue. Have you investigated why you are getting NULL for thumbnail in encodeWithCoder:?


#8

Thats is what i am unable to troubleshoot. I am pulling the images from CDATA section in a separate block in a separate thread and when i log the thumbnail from there, it gives me the memory locations but when i try to log them from encode and decode methods, it gives me NULL and i don’t know why.

Other than that, using the PNG representation also does not work. That is why i am asking for help!


#9

It looks like your image object is being released too soon. Can you post your code, all of it?


#10

I think i have found where exactly is the problem although i am not able to solve it as for now. Below is the CDATA block from where i am picking the images.

[code]-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
NSString *storyImageURL = [self getFirstImageUrl:someString];

NSURL *tempURL = [NSURL URLWithString:storyImageURL];
    
NSData *tempData = [NSData dataWithContentsOfURL:tempURL];
thumbnail = [UIImage imageWithData];

});

}[/code]

If i use the above code as it is, the images won’t persist. But If i use the code without the dispatch_async block, then it starts persisting the images as well but the UI gets blocked till the whole thing loads up which is not a good practice. How can get the lazy loading without locking the user interface?


#11

I can see that you are using ARC (which may complicate things). But try the following to see if it helps.

First, consider using a property for thumbnail with strong attribute.

...
@property (strong) UIImage *thumbnail;
...

Then at the end of the dispatch_async’s block, schedule a request to set the thumbnail on the main thread :

-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
    dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
    NSString *storyImageURL = [self getFirstImageUrl:someString];
    
    NSURL *tempURL = [NSURL URLWithString:storyImageURL];
    NSData *tempData = [NSData dataWithContentsOfURL:tempURL];

    [self performSelectorOnMainThread:@selector (setThumbnailFromData:) withObject:tempData waitUntilDone:NO];
    });
}

- (void)setThumbnailFromData:(NSData *)data
{
    self.thumbnail = [UIImage imageWithData:data];

    // Debug
    NSLog (@"---> %s: %p %p", __PRETTY_FUNCTION__, data, thumbnail);
}

#12

[quote=“ibex10”]I can see that you are using ARC (which may complicate things). But try the following to see if it helps.

First, consider using a property for thumbnail with strong attribute.

...
@property (strong) UIImage *thumbnail;
...

Then at the end of the dispatch_async’s block, schedule a request to set the thumbnail on the main thread :

[code]
-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
NSString *storyImageURL = [self getFirstImageUrl:someString];

NSURL *tempURL = [NSURL URLWithString:storyImageURL];
NSData *tempData = [NSData dataWithContentsOfURL:tempURL];

[self performSelectorOnMainThread:@selector (setThumbnailFromData:) withObject:tempData waitUntilDone:NO];
});

}

  • (void)setThumbnailFromData:(NSData *)data
    {
    self.thumbnail = [UIImage imageWithData:data];

    // Debug
    NSLog (@"—> %s: %p %p", PRETTY_FUNCTION, data, thumbnail);
    }
    [/code][/quote]

Thanks a ton for replying and giving time. I have used the code that you provided but it didn’t work. The result is same. When i use dispatch_asyc or performSelectorOnMainThread, it does not persist images. When i don’t use dispatch_async or performSelectorOnMainThread, then it starts persisting but locks the user interface. Plus the images that are fetched from the web service loads in a weird way. The on screen images does not show up but when i scroll a little then the ones that are not on the screen loads first. Anyways i guess i have to keep on trying


#13

I am still unable to solve this issue :frowning: