2009-11-16 101 views
0

我是新來的Objective-C,XCode和iPhone的開發一般,我有一些與核心數據和NSXMLParser問題。iPhone上的NSXMLParser與核心數據保存對象不正確

遵循Apples的教程SeismicXML(用於NSXMLParser)和iPhone上的Core Data教程,我在將值分配給Managed Object Models的實體屬性時遇到了一個問題。

爲了解釋這種情況,我的代碼僅僅通過使用CoreData將currentParsedCharacterData分配給我的託管對象而不是SeismicXML項目使用的標準NSObject來區別於SeismicXML示例。

以下是我的管理對象的描述輸出。

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飼料的最後一個節點的值;恰好是經度,緯度。然而,在屬性賦值時記錄已分析的字符數據時,它是預期的(並且是正確的)值,但是當輸出該對象的描述時,所有字符串值都是錯誤的,並且數值/否則只是0或零。

任何建議將不勝感激。如果需要的話,我可以敲一個更小的項目,使用與我正在使用的相同的XML Feed來顯示此行爲。

編輯:

下面是我在做什麼,以獲取信息爲管理對象,這導致了同樣的錯誤一個簡短的例子。

爲了方便起見,我有項目的zip http://willb.ro/CoreDataProblemExample.zip

調試輸出2009-11-16 14:31:20.357 ShittyExample [4360:4d07]公司 描述: (實體:公司; ID:0x3f6e9e0 ;數據:{ companyDescription = 「鋪頂在零售 秒的領先名優產品」; companyID = 66136112; 名稱= 「鋪頂在零售秒的領先名優產品」;})

//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

我有完全相同的問題,我不與核心數據是初學者,但是這是我第一次解析XML和把它作爲核心數據對象。這個錯誤很奇怪。如果有人從蘋果站點的核心數據中獲得SeismicXML項目的例子,我們將非常感謝這種洞察! – PostCodeism 2010-10-21 21:13:52

回答

0

看來你要分配,你應該被複制。我不得不看到更多的代碼可以確定,但我幾乎可以肯定某個地方會解決你的問題。