我是Objective-C,XCode和iPhone开发的新手,我在使用Core Data和NSXMLParser时遇到了一些问题。
在遵循Apples的教程SeismicXML(适用于NSXMLParser)和iPhone上的核心数据教程时,我在为我的托管对象模型的实体属性分配值时遇到了一个问题。
为了解释这种情况,我的代码与SeismicXML示例不同,它使用CoreData将currentParsedCharacterData分配给我的托管对象,而不是SeismicXML项目使用的标准NSObject。
以下是我的托管对象的描述输出。
county = "-53.25354768,4.256547";
friendly = "-53.25354768,4.256547";
image = nil;
latitude = -53.253547684;
link = "-53.25354768,4.256547";
longitude = nil;
name = "-53.25354768,4.256547";
postcode = "-53.25354768,4.256547";
shopDescription = nil;
shopID = 0;
tag = "-53.25354768,4.256547";
tags = (
);
telephone = "-53.25354768,4.256547";
town = "-53.25354768,4.256547";
似乎正在发生的是,所有属性/属性都分配了XML Feed中最后一个节点的值;这恰好是经度,纬度。然而,当在属性赋值时记录解析的字符数据时,它是预期的(和正确的)值,但是在输出此对象的描述时,所有字符串值都是错误的,而数值/否则只是0或nil。
任何建议都将非常感谢。如果需要的话,我可以使用与我正在使用的XML Feed相同的方式来打开一个显示此行为的较小项目。
编辑:
以下是我为了将信息导入托管对象而导致相同错误的缩写示例。
为方便起见,我有一个项目http://willb.ro/CoreDataProblemExample.zip
的拉链调试输出2009-11-16 14:31:20.357 ShittyExample [4360:4d07]公司 描述: (entity:Company; id:0x3f6e9e0 ;数据:{ companyDescription =“Top Shop是零售业中的领先品牌 秒“; companyID = 66136112; name =“Top Shop是零售业中的领先品牌”; })
//XML
<channel>
<company id="1">
<name>Top Shop</name>
<description>Top Shop are a leading brandname in the retail sector.</description>
</company>
</channel>
// FeedImporter.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class RootViewController, Company;
@interface FeedImporter : NSObject {
NSManagedObjectContext *managedObjectContext;
RootViewController *rootViewController;
NSMutableArray *companyList;
// for downloading the xml data
NSURLConnection *companyFeedConnection;
NSMutableData *companyData;
// these variables are used during parsing
Company *currentCompanyObject;
NSMutableArray *currentParseBatch;
NSUInteger parsedCompaniesCounter;
NSMutableString *currentParsedCharacterData;
BOOL accumulatingParsedCharacterData;
BOOL didAbortParsing;
}
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) RootViewController *rootViewController;
@property (nonatomic, retain) NSMutableArray *companyList;
@property (nonatomic, retain) NSURLConnection *companyFeedConnection;
@property (nonatomic, retain) NSMutableData *companyData;
@property (nonatomic, retain) Company *currentCompanyObject;
@property (nonatomic, retain) NSMutableString *currentParsedCharacterData;
@property (nonatomic, retain) NSMutableArray *currentParseBatch;
- (void)parseFeed;
- (void)addCompaniesToList:(NSArray *)companies;
- (void)handleError:(NSError *)error;
@end
// FeedImporter.m
#import "FeedImporter.h"
#import "RootViewController.h"
#import <CFNetwork/CFNetwork.h>
#import "Company.h"
@implementation FeedImporter
@synthesize managedObjectContext;
@synthesize rootViewController;
@synthesize companyList;
@synthesize companyFeedConnection;
@synthesize companyData;
@synthesize currentCompanyObject;
@synthesize currentParseBatch;
@synthesize currentParsedCharacterData;
- (void)dealloc {
[super dealloc];
[managedObjectContext release];
[rootViewController release];
[companyList release];
[companyFeedConnection release];
[companyData release];
[currentCompanyObject release];
[currentParseBatch release];
[currentParsedCharacterData release];
}
- (id)init {
if(self = [super init]) {
// Custom loading logic goes here..
}
return self;
}
- (void)parseFeed {
static NSString *feedURLString = @"http://willb.ro/companies.xml";
NSURLRequest *companyURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
self.companyFeedConnection = [[[NSURLConnection alloc] initWithRequest:companyURLRequest delegate:self] autorelease];
NSAssert(self.companyFeedConnection != nil, @"Failure to create URL connection.");
// Start the status bar network activity indicator. We'll turn it off when the connection finishes or experiences an error.
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.companyData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[companyData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if ([error code] == kCFURLErrorNotConnectedToInternet) {
// if we can identify the error, we can present a more precise message to the user.
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedString(@"No Connection Error", @"Error message displayed when not connected to the Internet.") forKey:NSLocalizedDescriptionKey];
NSError *noConnectionError = [NSError errorWithDomain:NSCocoaErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:userInfo];
[self handleError:noConnectionError];
} else {
// otherwise handle the error generically
[self handleError:error];
}
self.companyFeedConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.companyFeedConnection = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[NSThread detachNewThreadSelector:@selector(parseCompanyData:) toTarget:self withObject:companyData];
self.companyData = nil;
}
- (void)parseCompanyData:(NSData *)data {
// You must create a autorelease pool for all secondary threads.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.currentParseBatch = [NSMutableArray array];
self.currentParsedCharacterData = [NSMutableString string];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];
if ([self.currentParseBatch count] > 0) {
[self performSelectorOnMainThread:@selector(addCompaniesToList:) withObject:self.currentParseBatch waitUntilDone:NO];
}
self.currentParseBatch = nil;
self.currentCompanyObject = nil;
self.currentParsedCharacterData = nil;
// Save to our MOC...
NSError *saveError;
if(![self.managedObjectContext save:&saveError]) {
// Handle MOM save error
NSLog(@"error while saving shop to managed object model");
NSError* error;
if(![[self managedObjectContext] save:&error]) {
NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(@" DetailedError: %@", [detailedError userInfo]);
}
}
else {
NSLog(@" %@", [error userInfo]);
}
}
}
else
{
NSLog(@"MOC saved sucessfully");
}
[parser release];
[pool release];
}
#pragma mark Parser constants
// Limit the number of parsed companies to 50.
static const const NSUInteger kMaximumNumberOfCompaniesToParse = 50;
static NSUInteger const kSizeOfCompanyBatch = 10;
static NSString * const kChannelElementName = @"channel";
static NSString * const kCompanyElementName = @"company";
static NSString * const kCompanyNameElementName = @"name";
static NSString * const kCompanyDescriptionElementName = @"description";
- (void)addCompaniesToList:(NSArray *)companies {
[self.companyList addObjectsFromArray:companies];
// The table needs to be reloaded to reflect the new content of the list.
[rootViewController.tableView reloadData];
}
#pragma mark NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (parsedCompaniesCounter >= kMaximumNumberOfCompaniesToParse) {
didAbortParsing = YES;
[parser abortParsing];
}
if ([elementName isEqualToString:kCompanyElementName]) {
Company *company = (Company *)[NSEntityDescription insertNewObjectForEntityForName:@"Company" inManagedObjectContext:self.managedObjectContext];
self.currentCompanyObject = company;
[company release];
int companyIDInt = (int)[attributeDict valueForKey:@"id"];
NSNumber *companyID = [NSNumber numberWithInt:companyIDInt];
[self.currentCompanyObject setCompanyID:companyID];
}
else if ([elementName isEqualToString:kCompanyElementName] || [elementName isEqualToString:kCompanyNameElementName] || [elementName isEqualToString:kCompanyDescriptionElementName]) {
accumulatingParsedCharacterData = YES;
[currentParsedCharacterData setString:@""];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:kCompanyElementName]) {
//NSLog(@"currentEarthquakeObject: %@", currentEarthquakeObject);
[self.currentParseBatch addObject:self.currentCompanyObject];
parsedCompaniesCounter++;
if (parsedCompaniesCounter % kSizeOfCompanyBatch == 0) {
[self performSelectorOnMainThread:@selector(addCompaniesToList:) withObject:self.currentParseBatch waitUntilDone:NO];
self.currentParseBatch = [NSMutableArray array];
}
//NSLog(@"Reached end of company. Follows is a description of our company object: %@", [self.currentCompanyObject description]);
NSLog(@"Company Description: %@", [self.currentCompanyObject description]);
}
else if ([elementName isEqualToString:kCompanyNameElementName]) {
// Company Name
[self.currentCompanyObject setName:self.currentParsedCharacterData];
//NSLog(@"%@",self.currentParsedCharacterData);
}
else if ([elementName isEqualToString:kCompanyDescriptionElementName]) {
// Company Description
[self.currentCompanyObject setCompanyDescription:self.currentParsedCharacterData];
//NSLog(@"%@",self.currentParsedCharacterData);
}
accumulatingParsedCharacterData = NO;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (accumulatingParsedCharacterData) {
[self.currentParsedCharacterData appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
if (didAbortParsing == NO) {
[self performSelectorOnMainThread:@selector(handleError:) withObject:parseError waitUntilDone:NO];
}
}
- (void)handleError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error Title", @"Title for alert displayed when download or parse error occurs.") message:errorMessage delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
}
@end
答案 0 :(得分:0)
您似乎正在指定应该复制的位置。我必须看到更多代码才能确定,但我几乎可以肯定copy
某处可以解决您的问题。
答案 1 :(得分:0)
如上所述,我有完全相同的问题。但现在建议绕过无用的NSXMLParser(如果使用它与核心数据!!!)并使用GDataXML代替。 GDataXML是在NSXMLDocument类上建模的(这是一个更优雅,更实用的解决方案,可以与核心数据一起使用,只有你不能在iOS上使用NSXMLDocument)。
请在此处查看优秀教程: http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml :)