「The Big Nerd Ranch Guide」(第 3 版) の優れた例「Parsing XML with NSXMLParser」に基づいて、NSManagedObjects
XML 解析を追加したいカテゴリを my に追加しました。これらのカテゴリは、解析機能のみを提供します。
これは、これらのカテゴリを実装した方法です: .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 要素をさらに処理するようにします。親に。
これが、親デリゲートを子に格納する必要がある理由です。ただし、ivar とプロパティはカテゴリでは許可されていません。
この問題を回避すると思われるこの解決策を思いつきました:
子要素、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 ではないように見える変数にデリゲートを親に保存します。
このコードは私のテストではうまく機能し、開発プロセスの後半で問題になる何かを見逃したのか、それともこの設計は問題ないのか疑問に思っています。
それについてどう思いますか。
ありがとうございました!