2012-03-08 4 views
5

До IOS 5.1, если вы хотите использовать протоколы NSCoding с UIImage, вам нужно было сделать что-то вроде этого.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

Этот вопрос уже был задан и в то время это я ответил - я не помню, какой вопрос, потому что это было еще летом, но я могу вспомнить, есть дубликат этого вопроса. –

+0

Ах, вот он: http://stackoverflow.com/questions/11950173/conditional-categories-in-mountain-lion/11950348#11950348 –

ответ

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 

До сих пор я не заметила дальнейшую проблему. Надеюсь, это поможет!

[ВНИМАНИЕ]

Если вы используете эту UIImage категорию для того, чтобы архивировать UIImageViewer объекты, нужно учитывать, что реализация NSCoding из UIImageViewer в IOS 5, кажется, сломана. Свойство изображения UIImageViewer теряется после сохранения и загрузки, когда оно указано в XIB (я не пытался увидеть, есть ли такая же проблема, когда объект UIImageViewer создается в коде). Это было исправлено в прошивке 6.

[ОБНОВЛЕНИЕ]

Я изменил код, чтобы добавить методы + нагрузки вместо инициализации(), он по-прежнему выполняется только один раз, но раньше. Моя текущая реализация:

#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 NSStrings и UIImage, будет ли он включен? –

+0

Вышеупомянутый код реализован как категория UIImage.В основном то, что я сделал, просто расширяет то, что реализовал Джефф ЛаМарче (http://iphonedevelopment.blogspot.it/2009/03/uiimage-and-nscoding.html), чтобы избежать предупреждения в iOS 5.1. – szemian

+0

ah Я вижу, спасибо за это :) –

0

Один из способов - динамически исправить класс UIImage, чтобы добавить необходимые методы при работе на iOS 4 (или лучше, когда методы отсутствуют). Here’s a sample project on GitHub, который делает что-то подобное, добавляет поддержку поддержки контроллера для iOS 4 (клавишей является функция class_addMethod). Но это слишком магия для производственного кода, поэтому, если есть более простой ответ, пойдите с ним.

+0

Почему это слишком много волшебства для производственного кода? – odyth

+0

Сбрасывание классов с использованием среды выполнения является хрупким, трудно предвидеть проблемы, которые могут возникнуть. – zoul

2

Вместо того, чтобы использовать категорию в UIImage, не было бы ее легче подклассифицировать?

Тогда вы могли бы реализовать initWithCoder и encodeWithCoder и использовать реализацию NSCoding UIImage на 5.1 и свой собственный на pre-5.1.

+1

Есть только одно место, где мне нужно сохранить UIImage, для подкласса потребуется, чтобы я всегда использовал этот новый класс изображений, который я придумал. – odyth

+0

+1: состав> подклассификация (по-моему) – nielsbot