2009-11-16 1 views
0

Objective-C, XCode 및 iPhone 개발이 처음인데 Core Data 및 NSXMLParser와 관련된 문제가 있습니다.Object 저장 대상의 NSXMLParser 코어 데이터가 잘못되었습니다.

Apples의 튜토리얼 SeismicXML (NSXMLParser의 경우) 및 iPhone 튜토리얼의 핵심 데이터 Managed Object Models의 엔티티 속성에 값을 할당 할 때 문제가 발생했습니다.

내 코드는 CoreData를 사용하여 SeismicXML 프로젝트에서 사용하는 표준 NSObject가 아닌 관리 대상 객체에 currentParsedCharacterData를 할당함으로써 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 또는 nil입니다.

모든 의견은 극명하게 평가 될 것입니다. 필자는 필자가 사용하고있는 것과 동일한 XML 피드로이 동작을 보여주는 더 작은 프로젝트를 시작할 수 있습니다.

편집 : 여기

내가 같은 오류가 발생하는 관리 객체로 정보를 얻을 수 뭐하는 거지의 축약 된 예이다. 31 : 20.357 ShittyExample

는 편의상 나는 프로젝트의 우편 http://willb.ro/CoreDataProblemExample.zip

디버그 출력 2009-11-16 (14)이 [4360을 : 4d07] 회사 설명 : (기업 : 기업; ID : 0x3f6e9e0 , 데이터 : { companyDescription = "톱 숍 소매 초에서 선도적 한 brandname입니다"; 회사 ID = 66136112; 이름 = "톱 숍 소매 초에서 선도적 한 brandname입니다";})

//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을 구문 분석 및 핵심 데이터로 저장하는 것입니다 :

훌륭한 튜토리얼 여기를 참조하십시오 사물. 이 오류는 매우 이상합니다. Core 데이터가있는 Apple 사이트의 SeismicXML 프로젝트에 대한 사례가있는 사람이라면이 통찰력을 매우 높이 평가할 것입니다. – PostCodeism

답변

0

복사해야 할 위치를 지정하는 것 같습니다. 확신하기 위해 코드를 더 많이보아야하지만 어쨌든 copy 어딘가에 문제가 해결 될 것이라고 확신합니다.

0

위에서 언급 한 것과 똑같은 문제가있었습니다. 그러나 쓸데없는 NSXMLParser (핵심 데이터를 사용한다면 !!!)를 대신 사용하고 GDataXML을 대신 사용하는 것이 좋습니다. GDataXML은 NSXMLDocument 클래스에서 모델링됩니다 (핵심 데이터와 함께 사용하는보다 우아하고 실행 가능한 솔루션이며 iOS에서 NSXMLDocument를 사용할 수 없음). 내가 똑같은 문제가 있습니다 내가 핵심 데이터와 초보자 아니다 http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml :