2012-03-08 92 views
5

在iOS 5.1之前,如果你想在UIImage中使用NSCoding协议,你必须这样做。UIImage和NSCoding iOS 5.1

@interface UIImage (NSCoding) 

-(id)initWithCoder:(NSCoder *)deocder; 
-(void)encodeWithCoder:(NSCoder *)encoder; 

@end 

然后自己实施。但是,对于iOS 5.1,此协议的.M文件中会生成警告“类别正在实施一种方法,该方法也将由其主类实现”。现在,如果我删除这个扩展类iOS5.1会很高兴,但是这会在iOS4.0上崩溃和烧毁。那么最好的行动是什么?

+0

这个问题已经被问及当时这是我是谁的答案是 - 我不记得是怎样的问题,因为它是早在夏天,但我记得有一个重复这个问题在这里。 – 2012-10-06 08:44:19

+0

啊,这是它:http://stackoverflow.com/questions/11950173/conditional-categories-in-mountain-lion/11950348#11950348 – 2012-10-06 08:50:10

回答

7

我有同样的问题,因为它是来不及使用的子类,而不是cateogry,我也跟着zoul的建议,使用class_addMethod,以下是我的实现:

#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 

到目前为止,我还没有发现任何进一步的问题 希望它有帮助!

[注意]

如果为了存档UIImageViewer对象使用UIImage的类别,提防在iOS 5中NSCoding实施UIImageViewer似乎被打破。 UIImageViewer的image属性在保存和加载后会丢失,当它在XIB中指定时(我没有试图查看在代码中创建UIImageViewer对象时是否存在相同的问题)。这已被固定在IOS 6.

[UPDATES]

我改变代码添加在+负载方法,而不是初始化(),仍在只执行一次,但是早。我目前的执行情况:

#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

你介意提供一些关于这段代码去哪里的上下文吗?我有一个包含2个NSString和一个UIImage的自定义对象类,它会在那里? – 2012-06-20 10:34:51

+0

以上代码是作为UIImage的类别实现的。基本上我所做的只是扩展了Jeff LaMarche实施的功能(http://iphonedevelopment.blogspot.it/2009/03/uiimage-and-nscoding.html),以避免在iOS 5.1中出现警告消息。 – szemian 2012-06-20 10:47:07

+0

啊我看到了,谢谢:) – 2012-06-20 10:55:08

0

一种方法是动态修补UIImage类,以便在iOS 4上运行时(或更好,当方法丢失时)添加所需的方法。 Here’s a sample project on GitHub做了类似的事情,它增加了对iOS 4的控制器遏制支持(关键是class_addMethod函数)。但是这对于生产代码来说太过神奇了,所以如果有更简单的答案,那就去吧。

+0

为什么这对生产代码来说太神奇了? – odyth 2012-03-19 22:36:19

+0

使用运行时的类进行捣乱是很脆弱的,很难预见可能出现的问题。 – zoul 2012-03-20 07:10:54

2

而不是在UIImage上使用一个类别,它不是更清洁的子类吗?

然后,您可以实现initWithCoderencodeWithCoder并在5.1之前和5.1之前使用UIImage的NSCoding实现。

+1

只有一个地方我需要保存UIImage,子类化将要求我总是使用我发明的这个新的Image类。 – odyth 2012-03-19 22:45:49

+0

+1:作文>子类(在我看来) – nielsbot 2012-10-06 09:04:53