UIImage и NSCoding для iOS 5.1
До iOS 5.1, если вы хотели использовать протоколы NSCoding с UIImage, вы должны были сделать что-то вроде этого.
@interface UIImage (NSCoding)
-(id)initWithCoder:(NSCoder *)deocder;
-(void)encodeWithCoder:(NSCoder *)encoder;
@end
Тогда реализуй это сам. Однако с iOS 5.1 это генерирует предупреждение "Категория реализует метод, который также будет реализован его основным классом" в файле.M для этого протокола. Теперь, если я удалю это расширение, класс iOS5.1 будет счастлив, однако это должно вылететь и сгореть на iOS4.0. Итак, каков наилучший курс действий?
3 ответа
У меня та же проблема, и поскольку уже слишком поздно использовать подкласс, а не категрию, я последовал предложению 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
До сих пор я не заметил никаких дальнейших проблем. Надеюсь, поможет!
[ВНИМАНИЕ]
Если вы используете эту категорию UIImage для архивации объектов UIImageViewer, имейте в виду, что реализация UIImageViewer в iOS 5 в NSCoding кажется сломанной. Свойство image UIImageViewer теряется после сохранения и загрузки, когда оно указано в XIB (я не пытался увидеть, существует ли такая же проблема при создании объекта UIImageViewer в коде). Это было исправлено в 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, не будет ли чище подкласс ее?
Тогда вы могли бы реализовать initWithCoder
а также encodeWithCoder
и использовать реализацию NSCoding UIImage на 5.1 и свою собственную на pre-5.1.
Одним из способов является динамическое исправление UIImage
Класс для добавления необходимых методов при работе на iOS 4 (или лучше, когда методы отсутствуют). Вот пример проекта на GitHub, который делает нечто подобное, добавляет поддержку сдерживания контроллера для iOS 4 (ключ class_addMethod
функция). Но это слишком много волшебства для производственного кода, поэтому, если есть более простой ответ, соглашайтесь.