일단 이전에 만든 XML은 진짜 기본적인 Parser인거 같다... 내가 실제로 XML Parser를 사용함으로써 수많게 유용하고 유연하게
바꾸었다. 어떤 XML이 들어와도 읽을수 있게(이건 오버인가?..)
일단 발전된 상황이라면 모든 XML을 Dictionary로 관리하기 때문에 유연하게 바뀌었다.
XML Parser에서 initWithContentsOfURL을 이용하면 네트워크가 안될시나 URL이 잘못되면 어떠한 예외를 던지지 못하고 멈추는 현상이 있어서
일단 나는 파싱하기전에 그 URL이 XML을 정상적으로 리턴하는지 검증하는것이 필요 하였다.
원리는 이렇다.
일단 XML받는부분을 Background에서 실행한다.
[self performSelector:@selector(getTime) withObject:nil];
그리고 아래 예제처럼하였다.
- (void) getTime
{
NSString *serverIP = [[NSUserDefaults standardUserDefaults] objectForKey:@"ServerIP"];
NSURL* url =[NSURL URLWithString:[[NSString stringWithFormat:TimeElementsURL,serverIP]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
XmlManager* xmlManager= [[XmlManager alloc] init];
NSData* xmlData = [xmlManager GetXmlData:url isPostData:NO];
if(xmlData != nil) {
NSMutableDictionary *xmlDict= [xmlManager GetXmlDictDataByData:xmlData elementFile:@"TimeElements.plist"];
NSUserDefaults *timeData = [NSUserDefaults standardUserDefaults];
[timeData setObject:xmlDict forKey:@"TimeData"];
[timeData synchronize];
//시간 설정
currentTime = [[xmlDict objectForKey:@"TimeSec"] intValue];
int secs = currentTime % 60;
int mins = (currentTime % 3600) / 60;
int hours = currentTime / 3600;
timeRemainLabel.text = [NSString stringWithFormat:@"%.2d:%.2d:%.2d",hours, mins, secs];
}
else {
NSLog(@"time data 얻기 실패");
}
[xmlManager release];
}
소스는 거창하지만 실제로 보면
NSData* xmlData = [xmlManager GetXmlData:url isPostData:NO];
이부분을 보면 된다. 내가 구현한 xmlManager는 파일첨부 할것이다.
저렇게 일단 XML을 파싱하기전에 파싱데이터를 가져온다.
만약 저기서 data를 못받으면(data == nil) 실패했다고 말해준다.
이것이 바로 검증인것이다.
실패했는지 성공했는지 결과를 알수 있다는것이다.
성공하면 이렇게 파싱한다.
NSMutableDictionary *xmlDict= [xmlManager GetXmlDictDataByData:xmlData elementFile:@"TimeElements.plist"];
그리고 elementFile은 plist를 만들어서
이렇게 만든다.
NSManager에 GetXmlData 소스는 이렇다.
-(NSData*)GetXmlData:(NSURL*) url isPostData:(BOOL) isPost
{
NSMutableURLRequest* feedRequest = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
if(isPost == YES)
{
[feedRequest setHTTPMethod:@"POST"];
}
NSError* theError = nil;
NSData* xmlData = [NSURLConnection sendSynchronousRequest:feedRequest returningResponse:nil error:&theError];
// NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; //확인용
if(theError != nil || xmlData ==nil)
{
//네트워크가 잘못됬거나 data를 가져 오지 못했을 경우 nil return
return nil;
}
else
{
return xmlData;
}
2011년 10월 12일 추가
NSXmlparser버그로 인해서 첫글자가 숫자일경우 짤려서 foundCharacters가 두번 호출되는 버그가 있었다.
Xml에 들어온글중에 원래 xml의 element안에 있는글이
"1004 story에 들어오기. 나도 글을 잘 쓰고 싶을 뿐이다 ㅠㅠ"
라는 글이였는데
"에 들어오기. 나도 글을 잘 쓰고 싶을 뿐이다 ㅠㅠ"
만 나오는것이였다 보니까 1004 story라는 글이 짤려 있었다.
그래서 보니 첫글자가 숫자가 들어가니 아래 로그 처럼 나뉘어서 두번에 걸쳐서 foundCharacters delegate가 호출 되었다.
2011-10-12 11:09:01.447 나도 작가다[1151:207] CmtContent
2011-10-12 11:09:01.447 나도 작가다[1151:207] 1004 story , CmtContent
2011-10-12 11:09:01.448 나도 작가다[1151:207] count = 2, index= 0
2011-10-12 11:09:01.448 나도 작가다[1151:207] 에 들어오기. 나도 글을 잘 쓰고 싶을 뿐이다 ㅠㅠ , CmtContent
그래서 아래처럼 수정하였다.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//trim을 쓰자면 이걸 쓰고 안하면 그냥 string 값을 넣어도 된다.
NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmedValue = [string stringByTrimmingCharactersInSet:characterSet];
if([trimmedValue length] == 0)
{
return;
}
id element = [elementStack lastObject];
if([element isKindOfClass:[NSString class]])
{
NSUInteger count = [elementStack count];
NSUInteger index = count -2;
id parentElement = [elementStack objectAtIndex:index];
NSMutableDictionary *dataInfoDict = (NSMutableDictionary*)parentElement;
//NSXmlparser버그로 인해서 첫글자가 숫자일경우 짤려서 foundCharacters가 두번 호출된다.
if([element isEqualToString:@"CmtContent"])
{
if([[dataInfoDict allKeys] containsObject:element])
{
NSString* previousString = (NSString*)[dataInfoDict objectForKey:element];
trimmedValue =[previousString stringByAppendingString:trimmedValue];
}
}
[dataInfoDict setObject:trimmedValue forKey:element];
}
}
요약하자면 이전에 dictionary를 검색해서 이미 값이 있으면 이전 값과 현재 값을 합쳐서
저장한다.
만약 이전값이 없으면 무시되니깐 정상적으로 작동한다.
'iPhone App' 카테고리의 다른 글
[iphone] TableView Custom Cell에 버튼 이벤트 받기 (3) | 2011.09.23 |
---|---|
[iphone] 아이폰에서 ipaddress 얻어오기 (0) | 2011.09.22 |
[iphone] 데이터(XML)를 Post 방식으로 받아서 처리(WCF Rest) (0) | 2011.09.19 |
[iphone] tableviewcell에서 이미지 로딩을 백그라운드로 돌려서 성능 UP (0) | 2011.09.19 |
[iphone] table selection 안되게 하기 Disable (0) | 2011.09.19 |