基于“The Big Nerd Ranch Guide”(第3版)一书中的优秀示例“使用NSXMLParser解析XML”,我已经为我的NSManagedObjects
添加了类别,我想为其添加XML解析。这些类别仅提供解析功能。
这就是我实现这些类别的方式: .H:
#import "IBCompany.h"
@interface IBCompany (Xml) <NSXMLParserDelegate>
- (void)parseXmlString:(NSString*)xmlStr withCompletion:(void(^)(NSError *error))completionBlock;
@end
的.m:
@implementation IBCompany (Xml)
- (void)parseXmlString:(NSString*)xmlStr withCompletion:(void(^)(NSError *error))completionBlock;
{
NSData *xmlData = [xmlStr dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
parser.delegate = self;
[parser parse];
xmlData = nil;
NSError *error;
completionBlock(error);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"Issue"]) {
IBIssue *issue = [NSEntityDescription insertNewObjectForEntityForName:@"IBIssue" inManagedObjectContext:self.managedObjectContext];
issue.company = self;
issue.parentParserDelegate = self;
parser.delegate = issue;
}
正如您在此代码段中所看到的,我将解析器委托切换到其他子类/ XML子元素,以使它们进一步处理属于它们的下一个XML元素,直到到达XML元素的末尾并且委托被设置回父母。
这就是我需要将父委托存储在子代中的原因。但是,类别中不允许使用ivars和属性。
我提出了这个似乎可以解决这个问题的解决方案:
子元素,h:
#import "IBIssue.h"
@interface IBIssue (Xml) <NSXMLParserDelegate>
@property id parentParserDelegate;
@end
#import "IBIssue+Xml.h"
@implementation IBIssue (Xml)
NSMutableString *currentString;
NSString *currentXmlDocument;
id _parentParserDelegate;
- (id)parentParserDelegate
{
return _parentParserDelegate;
}
- (void)setParentParserDelegate:(id)parentParserDelegate;
{
_parentParserDelegate = parentParserDelegate;
}
- (NSDateFormatter*)dateFormatter
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setDateFormat:@"yyy-MM-dd"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT: 0]];
return dateFormatter;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"IssueID"]) {
currentString = [[NSMutableString alloc]init];
if ([attributeDict[@"Type"] isEqualToString:@"Ticker"]) self.ticker = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"Name"]) self.issueName = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"CUSIP"]) self.cusip = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"ISIN"]) self.isin = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"RIC"]) self.ric = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"SEDOL"]) self.sedol = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"DisplayRIC"]) self.displayRic = currentString;
else if ([attributeDict[@"Type"] isEqualToString:@"InstrumentPI"]) ; //
else if ([attributeDict[@"Type"] isEqualToString:@"QuotePI"]) ; //
} else if ([elementName isEqualToString:@"Exchange"]) {
currentString = [[NSMutableString alloc]init];
self.exchangeCode = attributeDict[@"Code"];
self.exchangeCountry = attributeDict[@"Country"];
self.exchange = currentString;
} else if ([elementName isEqualToString:@"MostRecentSplit"]) {
currentString = [[NSMutableString alloc]init];
self.mostRecentSplitDate = [self.dateFormatter dateFromString:attributeDict[@"Date"]];
// self.mostRecentSplit = [NSNumber numberWithFloat: currentString.floatValue];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// NSLog(@"appendString: %@", string);
[currentString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"Issue"]) {
parser.delegate = self.parentParserDelegate;
} else if ([elementName isEqualToString:@"MostRecentSplit"]) {
self.mostRecentSplit = [NSNumber numberWithFloat: currentString.floatValue];
}
currentString = nil;
}
@end
我将委托保存在变量_parentDelegate
中,该变量在ivar声明块之外声明,并且似乎不是真正的ivar。
这段代码在我的测试中效果很好,我想知道我是否遗漏了一些在开发过程后期会成为问题的东西,或者这个设计是否合适。
你对此有何看法?
谢谢!
答案 0 :(得分:0)
我不确定编译器如何处理该变量。它是否可以分配,以便这种类型的所有对象只共享一个变量?如果您的XML被解析为在某个时间点存在多个IBCompany,则可能导致问题。我写了一个测试,分配了两个IBCompany对象,导致它们都向_parentDelegate写入不同的值,然后断言值不同。
如果不可能并行解析两个IBCompany对象,则忽略该问题。您必须确保XML不能在另一个IBCompany中包含IBCompany,XML的多个部分不会并行处理,并且不会并行处理多个XML文档。
我认为不需要类别。当您不应该将子类写入现有类时,类别很有用,例如向Cocoa框架中的类添加功能。您正在编写自定义子类,那么为什么不将ivar添加到子类中?您可以在托管对象中具有未保存在Core Data后备存储中的其他ivars。最多我只使用一个扩展来将XML解析代码与托管对象的其余部分隔离开来。