Unarchiving UIImageView with subviews

I’m going a bit crazy trying to archive and unarchive a UIImageView which has number of subviews which are custom views derived from UIImageView. Here’s what I’ve done:

Add a category to the project to allow for the fact that UIImage does not conform to NSCoding:

  • UIImageView resizes automatically
  • How to create UIImageView with image from a link?
  • Tap gesture is not working in imageView but it working another view
  • UITapGestureRecognizer not working in UIImageView
  • Image is not fit to the frame of UIImageView
  • how do i alter the position of a UIImage inside a imageView SWIFT
  • #import "UIImage-NSCoding.h"
    #define kEncodingKey @"UIImage"
    
    @implementation UIImage(NSCoding)
    
    - (id)initWithCoder:(NSCoder *)decoder
    {
        if ((self = [super init]))
        {
            NSData *data = [decoder decodeObjectForKey:kEncodingKey];
            self = [self initWithData:data];
        }        
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder
    {
        NSData *data = UIImagePNGRepresentation(self);
        [encoder encodeObject:data forKey:kEncodingKey];
    }
    
    @end
    

    The UIImageView I’m archiving is a property of my main view controller called “background”. I save it like this:

    NSData *dataToSave = [NSKeyedArchiver archivedDataWithRootObject:self.background];
    [dataToSave dataWithContentsOfFile:imagePath options:NSDataWritingAtomic error:nil];
    

    Then later I unarchive it like this:

    NSData *savedData = [NSData dataWithContentsOfFile:imagePath];    
    UIImageView *restoredImageView = [NSKeyedUnarchiver unarchiveObjectWithData:savedData];
    self.background.image = restoredImageView.image; // this works - archived image is displayed
    

    Now I want to get my subviews (or one of them at least!) to display along with the unarchived root object:

    NSLog(@"Subviews: %d", [restoredImageView.subviews count]); // this tells me my subviews have been archived along with the root object
    NSLog(@"Subview 0: %@", [restoredImageView.subviews objectAtIndex:0]); // and they exist as expected
    
    NSLog(@"Subviews: %d", [self.background.subviews count]); // at this point no subviews are present
    [self.background addSubview:[restoredImageView.subviews objectAtIndex:0]]; // subview is not visible on screen
    NSLog(@"Subviews: %d", [self.background.subviews count]); // count is one, but where is it?
    
    ORUImageView *oru = [[ORUImageView alloc] init]; // I try creating the subview myself
    oru = [self.background.subviews objectAtIndex:0]; 
    [self.background addSubview:oru]; // it still doesn't show on screen
    [self.background bringSubviewToFront:oru]; // makes no difference
    
    NSLog(@"String: %@", oru.testString); // this correctly logs the test string I added to my custom class
    

    This is what I’ve added to my ORUImageView subclass:

    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        [super encodeWithCoder:aCoder];    
        [aCoder encodeObject:self.testString forKey:@"theString"];
        [aCoder encodeObject:self.image forKey:@"theImage"]; // not sure if this is needed
    }
    
    
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super initWithCoder:aDecoder];
        [self setTestString:[aDecoder decodeObjectForKey:@"theString"]];
        [self setImage:[aDecoder decodeObjectForKey:@"theImage"]]; // not sure if this is needed
        return self;
    }
    

    I’ve tried this with and without the encoding for the image property.

    I’m suspect the problem is related to this property as I’m clearly getting the subview added to the unarchived view – it’s just not visible! I feel the image property is not getting set, but I can’t find a way to set it myself and I can’t find anything that tells me the correct way to do this.

    Solutions Collect From Internet About “Unarchiving UIImageView with subviews”

    [Previous answer deleted.]

    EDIT: Hmm. I just tried this:

    - (IBAction)doButton1:(id)sender {
        theData = [NSKeyedArchiver archivedDataWithRootObject:iv];
        [iv removeFromSuperview];
        iv = nil;
    }
    
    - (IBAction)doButton2:(id)sender {
        iv = [NSKeyedUnarchiver unarchiveObjectWithData:theData];
        [self.view addSubview:iv];
    }
    

    It worked – with an ordinary UIImageView. So now I guess I don’t understand what you’re getting at; it appears that a UIImageView is already archived with its image. So you must be trying to solve some other problem. But I’m not grasping what the problem is.