0

我正在尝试解析从带有NSXMLParserDelegate. 我想要将NSObject数据放入(我将称之为MyObject@property的 s 不是NSStrings(有一些NSDates,一些NSNumbers,也许在未来的某个时候会出现一些原语)。

由于 XML 都是一个大字符串,因此当我尝试将 XML 中的值直接放入我的属性时(我[myObject setValue:currentElementValue forKey:elementName];在我的 中使用parser:didEndElement:...,通常工作正常 - 何时key是 a NSString),我会遇到错误和崩溃。我真的没想到这会奏效,但我认为值得一试。

最简单的方法就是对所有内容进行硬编码,所以如果我有一个'@property (nonatomic, strong) NSNumber *age;' 在我的对象上,当我找到<age>25</age>我的 XML 的一部分时,我会找到MyObject.age = [NSNumber numberWithInt:[currentElementValue intValue]];. 这样做的问题是它非常死板——我希望这段代码比那更动态。我不想提前知道我的对象的所有属性是什么。

我还尝试检查class该属性是什么,然后在输入值之前进行一些转换(例如[myObject setValue:[NSNumber numberWithInt:[currentElementValue intValue] forKey:elementName];if 属性isKindOfClass:[NSNumber class]]。问题是这是第一次使用该属性,所以它是nil, 和因此没有类。所以这种方法也不起作用。

我这样做完全错了吗?从 XML 获取数据并将其放入非NSString变量中似乎应该是相当典型的,但我似乎无法让它工作。

如果有人需要查看更多代码以更好地了解我的设置方式或我已经尝试过的内容,请告诉我。


编辑:我想出了一个我正在尝试做的快速示例。假设我有以下 XML:

<Object>
    <ITEM_NUMBER>4</ITEM_NUMBER>
    <IS_AWESOME>YES</IS_AWESOME>
    <AWESOMENESS>9000.1</AWESOMENESS>
</Object>

我想解析成MyObject(一个NSObject子类)的一个实例

@interface MyObject: NSObject

@property (nonatomic, assign) int ITEM_NUMBER;
@property (nonatomic, assign) BOOL IS_AWESOME;
@property (nonatomic, assign) float AWESOMENESS;

@end

还有第二个 XML

<OtherObject>
    <PRICE>4.99</PRICE>
    <QUANTITY>5</QUANTITY>
    <FOR_RESALE>NO</FOR_RESALE>
</OtherObject>

这将进入OtherObject(也是NSObject子类)的一个实例

@interface OtherObject: NSObject

@property (nonatomic, assign) int QUANTITY;
@property (nonatomic, assign) BOOL FOR_RESALE;
@property (nonatomic, assign) float PRICE;

@end

我想创建一个“模板”解析器(它具有@property (nonatomic, strong) NSObject *instance;然后NSMutableString *currentElementValue作为 ivar)

...
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [currentElementValue setString:string];
}

- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([[self.instance valueForKey:elementName] isKindOfClass:int])
    {
        [self.instance setValue:[currentElementValue intValue] forKey:elementName];
    }
    else if ([[self.instance valueForKey:elementName] isKindOfClass:float])
    {
        [self.instance setValue:[currentElementValue floatValue] forKey:elementName];
    }
    else if ([[self.instance valueForKey:elementName] isKindOfClass:BOOL])
    {
        [self.instance setValue:[currentElementValue boolValue] forKey:elementName];
    }
    else if ...
}
...

然后,我只是为每个不同的 XML 子类化该“模板”解析器并覆盖该init方法,以便

self.instance = [[MyObject alloc] init];

或者

self.instance = [[OtherObject alloc] init];

作为适当的。我有很多我正在调用的 web 服务,我将从中获得类似结构的 XML,因此只需在解析器中为每个更改 1 行是非常可取的。将所有其余的解析器代码放在一个“模板”类中将使维护、阅读和调试代码变得更加容易。

显然,我遇到的问题是isKindOfClass不接受int, float, 或BOOL作为输入。有什么类似的东西可以代替吗?

4

2 回答 2

1

问题在于这是第一次使用该属性,所以它是 nil,因此没有类。

Objective-C 允许在运行时查询类属性,因此自省属性类型并使用适当的转换是一种方法。

您可以在 Mike Ash 的博客上阅读更多关于运行时的信息,或者查看Objective C Introspection/Reflection

不过这个具体问题很多人都遇到过,所以解决的办法也不少:如iOS中所说的最成熟的REST服务库RESTKit就是这样一个库的一个很好的例子;MagicRecord 是另一个。

在决定实施自己的解决方案之前,您可以轻松地找到更多库来检查。

于 2013-11-15T20:03:02.553 回答
0

当然,我可以重写将所有属性分配为空值的init方法MyObject,这应该可以解决nil我在 OP 中引用的问题,但这感觉真的很hacky。虽然它可能是唯一的选择。


编辑:这种方法与 OP 中 EDIT 中的示例完全不同。KVC会将ints、floats、BOOLs全部转为NSNumbers,根本不知道它们原来在哪里。这意味着我将无法调用[currentElementValue intValue], [currentElementValue floatValue], 或[currentElementValue boolValue]视情况而定。

于 2013-11-07T16:56:05.300 回答