我正在尝试将NSJSONSerialization方法封装在Category
NSObject
上,而不是在整个代码中重复[de] /序列化。
#import <Foundation/Foundation.h>
@interface NSObject (AYIAdditions)
+ (NSString *)JSONString;
+ (id)objectFromJSONString;
+ (id)objectFromJSONData;
@end
但是,我收到错误:'NSMutableDictionary'没有可见的@interface声明选择器'JSONString'
NSMutableDictionary
继承NSObject
,因此应该继承这些类别方法,对吧?我错过了什么?
顺便说一句,使用类别是一种好方法(mentioned by Ray Wenderlich)。或者我应该只使用一些类方法创建一个自定义对象。
答案 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对象不能序列化。