3

我试图将NSJSONSerialization方法封装在一个Categoryon中,NSObject而不是在整个代码中重复 [de]/serialization。

。H

#import <Foundation/Foundation.h>

@interface NSObject (AYIAdditions)

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

@end

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

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

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

4

3 回答 3

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

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

于 2013-03-27T18:20:46.537 回答
0

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

#import "NSObject+AYIAdditions.h"

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

于 2013-03-27T18:14:21.263 回答
0

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

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

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

调用isValidJSONObject:或尝试转换是判断给定对象是否可以转换为 JSON 数据的确定方法。资料来源:Apple 的文档

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

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


另一种方法可能是确实在 NSObject 上声明类别,但传入一个失败块以处理 n 个对象不能序列化的情况。

于 2013-03-27T18:36:12.543 回答