iOS类别继承来封装NSJSONSerialization

时间:2013-03-27 18:10:38

标签: ios objective-c objective-c-category

我正在尝试将NSJSONSerialization方法封装在Category NSObject上,而不是在整个代码中重复[de] /序列化。

·H

#import <Foundation/Foundation.h>

@interface NSObject (AYIAdditions)

+ (NSString *)JSONString;
+ (id)objectFromJSONString;
+ (id)objectFromJSONData;

@end

但是,我收到错误:'NSMutableDictionary'没有可见的@interface声明选择器'JSONString'

NSMutableDictionary继承NSObject,因此应该继承这些类别方法,对吧?我错过了什么?

顺便说一句,使用类别是一种好方法(mentioned by Ray Wenderlich)。或者我应该只使用一些类方法创建一个自定义对象。

3 个答案:

答案 0 :(得分:5)

在代码中:

+ (NSString *)JSONString;

+(加号)表示类方法。您最有可能想要一个实例方法,如下所示:

- (NSString *)JSONString;

关于如何实现序列化的方法论:这完全是“搁置”。您要求的范围非常广泛,您提供的细节很少。这实际上取决于您的需求范围以及您希望投入多少时间/精力,而是权衡意见:

NSObject上的某个类别对我来说似乎有点过于宽泛。我认为它不可能产生比看起来更合乎逻辑的选择更好的结果。协议。

我坦率地希望NSJSONSerialization声明了一个用于序列化我们自己的自定义模型对象的协议,类似于NSCoding,但他们没有。这仍然是将对象编码为JSON时的路线。协议看起来像这样:

NSString * const MySerializationClassKey = @"MySerializationClassKey";
@protocol MySerializationProtocol <NSObject>
@required
-(NSDictionary *)dictionarySerialization;
-(id)initFromDictionarySerialization:(NSDictionary *)dictionary;
@end

然后您的自定义模型对象可以像这样序列化和反序列化:(过于简单化)

@interface MyModel() <MySerializationProtocol>
@property (strong) NSString *name;
@end
@implementation MyModel
NSString * const MyModelNameKey = @"MyModelNameKey";
@synthesize name = _name;
-(NSDictionary *)dictionarySerialization{
    // encode object as dictionary
    return @{MySerializationClassKey: NSStringFromClass(self.class), MyModelNameKey: _name.copy};
}
-(id)initFromDictionarySerialization:(NSDictionary *)dictionary{
    if ((self = [super init])){
        _name = [dictionary objectForKey:MyModelNameKey];
    }
    return self;
}
@end

现在假设,为了不在答案中键入完整的序列化库,您只有这些模型对象的平坦NSArray。您可以创建一个与这些方法配合使用NSJSONSerialization的类。为了使每次通话更容易,如下:

@interface MySerializer : NSObject
@end
@implementation MySerializer
+(NSData *)jsonDataFromObject:(NSMutableArray *)array{
    for (NSUInteger index = 0; index < array.count; index++) {
        NSObject *object = [array objectAtIndex:index];
        if ([object conformsToProtocol:@protocol(MySerializationProtocol)]){
            NSDictionary *dictRep = [(id<MySerializationProtocol>)object dictionarySerialization];
            [array replaceObjectAtIndex:index withObject:dictRep];
        }
    }
    return [NSJSONSerialization dataWithJSONObject:array options:0 error:nil];
}
+(NSMutableArray *)objectFromJSONData:(NSData *)data{
    NSMutableArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
    for (NSUInteger index = 0; index < array.count; index++) {
        NSObject *object = [array objectAtIndex:index];
        if ([object isKindOfClass:[NSDictionary class]]){
            NSDictionary *dict = (NSDictionary *)object;
            NSString *className = [dict objectForKey:MySerializationClassKey];
            if (className.length > 0) {
                NSObject *deserialized = [[NSClassFromString(className) alloc] initFromDictionarySerialization:dict];
                if (deserialized) [array replaceObjectAtIndex:index withObject:deserialized];
            }
        }
    }
    return array;
}
@end

现在显然要从这样的代码中获取任何里程数,你必须以递归方式遍历可能的数组和字典。但这是我的首选路线。

答案 1 :(得分:0)

您确定导入了该类别的标题吗?

#import "NSObject+AYIAdditions.h"

这是否是正确的方法是有争议的。我不认为向NSObject添加一个无法在所有对象上调用的方法是一个很好的解决方案(并非所有对象都可以通过JSON序列化)。

答案 2 :(得分:0)

  

您使用NSJSONSerialization类将JSON转换为Foundation   对象并将Foundation对象转换为JSON。

     

可以转换为JSON的对象必须具有以下内容   属性:

     
      
  • 顶级对象是NSArray或NSDictionary。
  •   
  • 所有对象都是   NSString,NSNumber,NSArray,NSDictionary或NSNull的实例。
  •   
  • 所有   字典键是NSString的实例。
  •   
  • 数字不是NaN或   无穷。其他规则可能适用。
  •   
     

致电isValidJSONObject:或   尝试转换是确定一个给定的确定方式   对象可以转换为JSON数据。 source:Apple's docs

所以你应该在NSObject上定义那个类别。一个有意义的地方是NSArray和NSDictionary。

我还会创建一个序列化程序类,它提供sharedSerializer,可以从这两个类别中调用。


另一种方法可能是确实在NSObject上声明类别,但传入一个故障块来处理案例n对象不能序列化。

相关问题