티스토리 뷰

반응형

출처 http://qiita.com/fumiyasac@github/items/02a7b962e9a2013c56a0


시작하기:Swift1.1 → Swift1.2 → Swift2.x에서 변경사항이 있는 NSXMLParser

현재는 API로부터 정보를 가져와서  UITableView에 표시하기 위한 처리를 하는 경우 Response는 JSON으로 하는 경우가 많이 있다고 생각됩니다.  Swift2.0에서도 XML의 해석 및 읽기 처리를 할 수 있습니다.(공개된 API는 거의 두가지 형식을 다 지원하는 경우가 많다)

주의점:parser 메소드의 attributes attributeDict:가 버젼마다 다릅니다.

parser메소드에 대해 특별히 크게 변경 된 점이 있는 것은 아래에 기술하였습니다.
또 그것을 처리하거나 기타 parser메소드에 대해서도 optional의 위치도 미묘하게 차이가 있으니 주의할 필요가 있습니다.

Swift1.1)

xxx.swift
parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: NSDictionary!)

↑attributeDictはNSDictonary!

Swift1.2)

xxx.swift
parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!)

↑attributeDictは[NSObject : AnyObject]!

Swift2.x)

xxx.swift
parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [String : String])

↑attributeDictは[String : String]

이런 이유로 각각의 버젼별 차이점이 있기 때문에 처리도 각각 해줘야 합니다. Swift2.0에서 XML를 해석하는 포인트를 깔끔하게 정리할려고 합니다.

코드:실제 처리에서 포인트가 되는 부분은 이것입니다.

■ 사용API:
이 예제는「과자의 포로」API를 이용합니다.
http://www.sysbird.jp/toriko/webapi/

  • 실제 이 API의 Response에 관해서는「과자의 포로」의 페이지를 참조해주세요
  • 이번에는 상기 API를 사용해서 랜덤 데이터를 30개 취득하는 것을 가정으로 기술되었습니다.
  • UITableView에 표시하는 내용은 아래 5개 입니다.
  1. 과자 이름
  2. 과자 썸네일
  3. 과자 메이커 이름
  4. 과자 카테고리
  5. 과자 가격


1. Delegate또는 변수의 준비

ViewController.swift(class선언부분)
//NSXMLParserDelegate를 기술
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSXMLParserDelegate

2. 멤버변수 또는 분석데이터를 저장하는 변수 준비

ViewController.swift(프로퍼티의 선언부분)

//XMLURL let feedUrl : NSURL = NSURL(string:"http://www.sysbird.jp/webapi/?apikey=guest&max=30&order=r")! //XML현재요소명 변수 var currentElementName : String! //취득한 요소명(시작요소명) let itemElementName : String = "item" //취득한 요소명 확정(item요소는 다음과 같음) let nameElementName : String = "name" let makerElementName : String = "maker" let priceElementName : String = "price" let typeElementName : String = "type" let urlElementName : String = "url" let imageElementName : String = "image" //각 엘리멘트용 변수 var posts = NSMutableArray() var elements = NSMutableDictionary() var element = NSString() var name = NSMutableString() var maker = NSMutableString() var price = NSMutableString() var type = NSMutableString() var url = NSMutableString() var image = NSMutableString()

3. viewDidLoad 처리

ViewController.swift(viewDidLoad内)

override func viewDidLoad() { super.viewDidLoad() //해석데이터 저장용 posts = [] //UITableView에 관한 처리를 기술 ...(중략)... //NSXMLParser클래스의 인스탄스 준비 let parser : NSXMLParser = NSXMLParser(contentsOfURL: feedUrl)! //XML파서 delegate parser.delegate = self //XML파서 실행 parser.parse() }

4. XML파서 처리실행개시시 처리

ViewController.swift(NSXMLParser)

//이번에 특별한 것이 없으니 공란 그대로 func parserDidStartDocument(parser: NSXMLParser) { }

5. XML파서 처리실행중에 수행할 작업(NSXMLParser)

item요소를 찾음
※XML의요소를 상단에서부터 조사해서 이미지를 처리한다.

ViewController.swift(viewDidLoad内)

func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { self.element = elementName //요소명이「item」 의요소가 보인 경우에는 위세 설정한 멤버변수를 초기화한다. if (elementName as NSString).isEqualToString(self.itemElementName){ self.elements = [:] self.name = "" self.maker = "" self.price = "" self.type = "" self.url = "" self.image = "" } }

6. XML파서 처리실행중에  수행할 작업(NSXMLParser)

item요소내에서 name・url・price・maker・url・image요소를 찾아 item요소를 발견했을 때 준비한 변수에 담아준다.

ViewController.swift(NSXMLParser)

func parser(parser: NSXMLParser, foundCharacters string: String){ if self.element.isEqualToString(self.nameElementName) { self.name.appendString( strip(string) ) } if self.element.isEqualToString(self.makerElementName) { self.maker.appendString( strip(string) ) } if self.element.isEqualToString(self.priceElementName) { self.price.appendString( strip(string) ) } if self.element.isEqualToString(self.typeElementName) { self.type.appendString( strip(string) ) } if self.element.isEqualToString(self.urlElementName) { self.url.appendString( strip(string) ) } if self.element.isEqualToString(self.imageElementName) { self.image.appendString( strip(string) ) } }

이대로라면 XML의 요소를 취득 할 때 여분의 줄 바꿈과 공백이 포함되어 버리므로, 줄 바꿈과 공백을 제거하는 방법도 추가해야 합니다.

ViewController.swift(NSXMLParser)

//줄 바꿈과 공백을 제거한다. func strip(str: String) -> String { var strBr: String var strSp: String //줄 바꿈 제거 strBr = str.stringByReplacingOccurrencesOfString("\n", withString: "", options: [], range: nil) //공백 제거 strSp = strBr.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil) return strSp }

7. XML파서 처리실행중에  수행할 작업(NSXMLParser)

태그의 마지막을 검출했을 때 꺼낸 요소에 부합한 경우에는 해석 데이터 저장용에 넣는다.

ViewController.swift(NSXMLParser)

func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if (elementName as NSString).isEqualToString(self.itemElementName) { //각 멤버변수가 nil이 아니면 멤버변수 elements에 '키'와 '값'을 쌍으로 저장한다. if !self.name.isEqual(nil) { self.elements.setObject(self.name, forKey: self.nameElementName) } if !self.maker.isEqual(nil) { self.elements.setObject(self.maker, forKey: self.makerElementName) } if !self.price.isEqual(nil) { self.elements.setObject(self.price, forKey: self.priceElementName) } if !self.type.isEqual(nil) { self.elements.setObject(self.type, forKey: self.typeElementName) } if !self.url.isEqual(nil) { self.elements.setObject(self.url, forKey: self.urlElementName) } if !self.image.isEqual(nil) { self.elements.setObject(self.image, forKey: self.imageElementName) } self.posts.addObject(self.elements) } }

마지막으로. Swift 버젼업 공식문서를 확인하자.

소스적으로는 깨끗하다고 말할 수 없습니다만,  XML의 해석처리 부분을 작성할 때 조금이나마 도움이 되었으면 하는 바램입니다.

이미지를 취득하는 처리는 이정도 하는게 좋지 않을까?

ViewController.swift(viewDidLoad内)

//화상 이미지요소의 데이터를 취득한 후에 nil 일 가능성을 체크한다. let q_global: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); let q_main: dispatch_queue_t = dispatch_get_main_queue(); let imageParameter: String! = (posts.objectAtIndex(indexPath.row).valueForKey("image")!.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)) //URL이 있다면 화상취득처리를 한다. if imageParameter != "" { //썸네일URL을 바탕을로 화상데이터(NSData형)을 작성 let imageURL = NSURL(string: imageParameter) //비동기로 URL데이터를 취득 dispatch_async(q_global,{ //썸네일URL을 바탕을로 화상데이터(NSData형)을 작성 var error: NSError? var imageData: NSData? //데이터를 취득 할수 있으면 정상처리 do { imageData = try NSData(contentsOfURL: imageURL!, options: []) //Error가 돌아온 경우는 imageData에 nil을 넣어준다. } catch let error1 as NSError { error = error1 imageData = nil //그거 이외는 예와 } catch { fatalError() } if error != nil { //nil의 경우 디폴트 이미지를 표시한다. let image: UIImage = UIImage(named: "no_image.gif")! cell!.okashiImage?.image = image } //갱신은 메인쓰레드에서 한다. dispatch_async(q_main,{ //이미지데이터가 nil이 아니라면 썸네일 이미지를 표시 if((imageData) != nil){ //xib의 썸네일영역을 표시한다. let image: UIImage = UIImage(data: imageData!)! cell!.okashiImage?.image = image cell!.layoutSubviews() } }) }) } else { //nil의 경우는 디폴트 이미지를 표시한다. let image: UIImage = UIImage(named: "no_image.gif")! cell!.okashiImage?.image = image }

실제 동작하는 소스:
https://github.com/fumiyasac/XMLFeedSample


반응형

'Mobile > iOS' 카테고리의 다른 글

[iOS] 필수로 사용하는 아이콘 사이즈.  (0) 2016.04.18
[예제]Captcha Generator for iOS  (0) 2016.04.08
iOS9의 화면사이즈  (0) 2016.04.06
[Swift2.2]RSS리더만들기  (0) 2016.04.05
[MAC]Page Down Key는 어디에?  (0) 2016.04.04
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함