Doing -initWithCoder: with NSData

Discussion in 'iOS Programming' started by idelovski, May 6, 2010.

  1. idelovski macrumors regular

    Joined:
    Sep 11, 2008
    #1
    In the source code I found in a book there's an implementation of -initWithCoder: that basically looks like this:
    Code:
    - (id)initWithCoder:(NSCoder *)decoder
    {
       if (self = [super init])  {
          NSData  *data = [decoder decodeObjectForKey:kImageKey]; 
          self = [self initWithData:data];
       }
       
       return (self);
    }
    But, this looks potentially problematic. Isn't something like this better and safer?
    Code:
    - (id)initWithCoder:(NSCoder *)decoder
    {
       NSData  *data = [decoder decodeObjectForKey:kImageKey];
          
       self = [self initWithData:data];
       
       return (self);
    }
    If super's init creates some internal variables directly, without accessing them through properties, then things allocated in first -init call would leak.
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    Yes I would not call init twice. However if you're subclassing a class that does conform to NSCoding you'd want to do it like this:
    Code:
    - (id)initWithCoder:(NSCoder *)decoder
    {
       if (self = [super initWithCoder:decoder])
          self.data = [decoder decodeObjectForKey:kImageKey];
       return self;
    }
    so watch out for what your superclass is.
     
  3. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #3
    Thanks,

    but, in this case the whole point was that the superclass does not conform to NSCoding. That is why, unlike your example, the code above creates complete instace of the class, not just one property.

    It is from the book by Deitels & co. and adds a category to UIImage to make it conform to NSCoding. Here's the complete listing, containing both original code an my modification.

    Code:
    @implementation UIImage (NSCoding)
    
    - (id)initWithCoder:(NSCoder *)decoder
    {
       // Old version
       // if (self = [super init])  {
       //    NSData  *data = [decoder decodeObjectForKey:kImageKey];
       // 
       //    self = [self initWithData:data]; // initialize the UIImage with data
       // }
       
       NSData  *data = [decoder decodeObjectForKey:kImageKey];
          
       self = [self initWithData:data]; // initialize the UIImage with data
       
       return (self);
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder
    {
       NSData *data = UIImagePNGRepresentation (self);    // get the PNG representation of the UIImage
    
       [encoder encodeObject:data forKey:kImageKey];
    }
    @end
    
     
  4. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #4
    The problem is that if you leave out the call to [super init], you may be skipping some initializing steps that need to take place for the superclass.
     
  5. idelovski thread starter macrumors regular

    Joined:
    Sep 11, 2008
    #5
    But -initWithData: of UIImage surely took care of that.

    self = [self initWithData:data] probably ends up doing something like if (self = [super init]) in the very first line of that method.

    It just can't be anything else.
     
  6. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #6
    Ah, sorry. Didn't realize you were adding a category to UIImage. My apologies.
     

Share This Page