UIImage and NSCoding iOS 5.1

后端 未结 3 380
醉话见心
醉话见心 2020-12-20 22:01

Prior to iOS 5.1 if you wanted to use NSCoding protocols with UIImage you had to do something like this.

@interface UIImage (NSCoding)

-(id)initWithCoder:(N         


        
相关标签:
3条回答
  • 2020-12-20 22:11

    Instead of using a category on UIImage, wouldn't it be cleaner to subclass it?

    Then you could implement initWithCoder and encodeWithCoder and use UIImage's NSCoding implementation on 5.1 and your own on pre-5.1.

    0 讨论(0)
  • 2020-12-20 22:23

    I have the same issue, and since it is too late to use subclass rather than cateogry, I followed zoul's suggestion to use class_addMethod, and below is my implementation:

    #import "UIImage-NSCoding.h"
    #include <objc/runtime.h>
    #define kEncodingKey        @"UIImage"
    
    static void __attribute__((constructor)) initialize() {
        @autoreleasepool {
    
            if (![[UIImage class] conformsToProtocol:@protocol(NSCoding)]) {
                Class class = [UIImage class];
    
                if (!class_addMethod(
                                     class,
                                     @selector(initWithCoder:), 
                                     class_getMethodImplementation(class, @selector(initWithCoderForArchiver:)),
                                     protocol_getMethodDescription(@protocol(NSCoding), @selector(initWithCoder:), YES, YES).types
                                    )) {
                                        NSLog(@"Critical Error - [UIImage initWithCoder:] not defined.");
                                    }
    
                if (!class_addMethod(
                                     class,
                                     @selector(encodeWithCoder:),
                                     class_getMethodImplementation(class, @selector(encodeWithCoderForArchiver:)),
                                     protocol_getMethodDescription(@protocol(NSCoding), @selector(encodeWithCoder:), YES, YES).types
                                    )) {
                                        NSLog(@"Critical Error - [UIImage encodeWithCoder:] not defined.");
                                    }
    
            } 
        }
    }
    
    @implementation UIImage(NSCoding)
    
    - (id) initWithCoderForArchiver:(NSCoder *)decoder {
    
        if ((self = [super init]))
        {
            NSData *data = [decoder decodeObjectForKey:kEncodingKey];
            self = [self initWithData:data];
        }
    
        return self;
    
    }
    
    - (void) encodeWithCoderForArchiver:(NSCoder *)encoder {
    
        NSData *data = UIImagePNGRepresentation(self);
        [encoder encodeObject:data forKey:kEncodingKey];
    
    }
    
    @end
    

    So far I have not noticed any further issue. Hope it helps!

    [ATTENTION]

    If you use this UIImage category in order to archive UIImageViewer objects, beware that NSCoding implementation of UIImageViewer in iOS 5 seems to be broken. The image property of the UIImageViewer is lost after save and load, when it is specified in XIB (I have not tried to see if there is the same issue when UIImageViewer object is being created in code). This has been fixed in iOS 6.

    [UPDATES]

    I changed my code to add methods in +load instead initialize(), it is still being executed only once, but earlier. My current implementation:

    #import "UIImage+NSCoding.h"
    #import <objc/runtime.h>
    #define kEncodingKey        @"UIImage"
    
    @implementation UIImage (NSCoding)
    
    + (void) load
    {
    
        @autoreleasepool {
            if (![UIImage conformsToProtocol:@protocol(NSCoding)]) {
                Class class = [UIImage class];
                if (!class_addMethod(
                                     class,
                                     @selector(initWithCoder:), 
                                     class_getMethodImplementation(class, @selector(initWithCoderForArchiver:)),
                                     protocol_getMethodDescription(@protocol(NSCoding), @selector(initWithCoder:), YES, YES).types
                                     )) {
                    NSLog(@"Critical Error - [UIImage initWithCoder:] not defined.");
                }
    
                if (!class_addMethod(
                                     class,
                                     @selector(encodeWithCoder:),
                                     class_getMethodImplementation(class, @selector(encodeWithCoderForArchiver:)),
                                     protocol_getMethodDescription(@protocol(NSCoding), @selector(encodeWithCoder:), YES, YES).types
                                     )) {
                    NSLog(@"Critical Error - [UIImage encodeWithCoder:] not defined.");
                }
    
            } 
        }
    }
    
    - (id) initWithCoderForArchiver:(NSCoder *)decoder {
        if (self = [super init]) {
            NSData *data = [decoder decodeObjectForKey:kEncodingKey];
            self = [self initWithData:data];
        }
    
        return self;
    
    }
    
    - (void) encodeWithCoderForArchiver:(NSCoder *)encoder {
    
        NSData *data = UIImagePNGRepresentation(self);
        [encoder encodeObject:data forKey:kEncodingKey];
    
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-20 22:24

    One way is to dynamically patch the UIImage class to add the needed methods when running on iOS 4 (or better, when the methods are missing). Here’s a sample project on GitHub that does something similar, it adds controller containment support for iOS 4 (the key is the class_addMethod function). But this is too much magic for production code, so if there’s a simpler answer, go with it.

    0 讨论(0)
提交回复
热议问题