UIImage和NSCoding的iOS 5.1

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

@interface UIImage (NSCoding) -(id)initWithCoder:(NSCoder *)deocder; -(void)encodeWithCoder:(NSCoder *)encoder; @end 

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

我有同样的问题,因为使用子类而不是cateogry为时已晚,所以我遵循zoul的build议来使用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 

到目前为止我还没有注意到任何进一步的问题 希望能帮助到你!

[注意]

如果您使用此UIImage类别来归档UIImageViewer对象,请注意,iOS 5中的UIImageViewer的 NSCoding实现似乎被破坏。 UIImageViewer的图像属性在保存和加载后,在XIB中指定时丢失(我没有试图查看在代码中创buildUIImageViewer对象时是否存在相同的问题)。 这已经在iOS 6中修复了。

[更新]

我改变了我的代码在+ load中添加方法,而不是initialize(),它仍然只执行一次,但是更早。 我目前的实施:

 #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 

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

然后你可以实现initWithCoderencodeWithCoder并在5.1之前使用UIImage的NSCoding实现,并在5.1之前使用你自己的。

一种方法是dynamic修补UIImage类,以在iOS 4上运行时添加所需的方法(或者更好,当方法丢失时)。 下面是GitHub上的一个样例项目 ,它增加了对iOS 4的控制器遏制支持(关键是class_addMethod函数)。 但是这对于生产代码来说太神奇了,所以如果有一个更简单的答案,就去做吧。