2017-04-17 33 views
0

我想使用URLSession解析JSON並且不使用Alamofire或其他任何東西。Swift 3使用URLSession將JSON解析爲UITableView

我只想把JSON放到UITableView中。

我想拼湊出我學習如何使用Alamofire解析JSON,以及我可以在Google上找到的東西。 youtube或Stack等許多答案使用NS的一切...... NSURL,NSDictionary等等。或者只是輸入代碼而不解釋什麼/爲什麼。

我想我已經差不多了,但我需要幫助瞭解我還有什麼要做。

SO。

我在PLST允許任意負載

在斯威夫特文件我有以下

class Potter { 

private var _title: String! 
private var _author: String! 
private var _imageURL: String! 

let POTTER_URL = "http://de-coding-test.s3.amazonaws.com/books.json" 

var title: String { 
    if _title == nil { 
    _title = "" 
    } 
    return _title 
} 

var author: String { 
    if _author == nil { 
    _author = "" 
    } 
    return _author 
} 

var imageURL: String { 
    if _imageURL == nil { 
    _imageURL = "" 
    } 
    return _imageURL 
} 

    func downloadJSON() { 


    let url = URL(string: POTTER_URL) 
    let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in 

     if error != nil { 
     print("Error") 

     } else { 

     if let content = data { 
      do { 
      if let jDict = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as? Dictionary<String, AnyObject> { 

       if let title = jDict["title"] as? String { 
       self._title = title.capitalized 

       } 

       if let author = jDict["author"] as? String { 
       self._author = author.capitalized 
       } 

       if let imgURL = jDict["imageURL"] as? String { 
       self._imageURL = imgURL 
       } 
      } 
      } 
      catch { 
      } 
     } 
     } 
    } 
    task.resume() 
    } 
} 

在我Main.Storyboard我加入的tableview,並設置了所有的UI,並在我的ViewController我建立了tableview代表。

我創造我現在被困在如何我填充這個數組的

var potters = [Potter]() 

的屬性,以及如何建立合適的穿線

回答

2

所有模型首先是 瘋狂 很奇怪。

In Swift 從來沒有使用支持的私有變量來獲取只讀屬性。而從不聲明屬性隱式解包可選,因爲你懶得寫一個初始化。

整個模型可以降低到

class Potter { 

    let title, author, imageURL: String 

    init(title: String, author: String, imageURL : String) { 
     self.title = title 
     self.author = author 
     self.imageURL = imageURL 
    } 
} 

如果你會用一個struct,因爲你得到的按成員初始化免費甚至

struct Potter { 
    let title, author, imageURL: String 
} 


其次,把方法downloadJSON()出來的模型,並把它的控制器,並調用它viewDidLoad()

在控制器聲明的下載URL和數據源陣列

let POTTER_URL = "http://de-coding-test.s3.amazonaws.com/books.json" 

var books = [Potter]() 

你的方法downloadJSON()不能工作,因爲JSON對象是一個數組([]),而不是一個字典({})。您需要一個循環遍歷項目,獲取值,分別創建一個Potter項目並將其附加到數據源。如果值不存在,則分配空字符串。最後重新加載主線程上的表格視圖。

func downloadJSON() { 

    let url = URL(string: POTTER_URL) 
    let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in 

     if error != nil { 
      print("DataTask error", error!) 

     } else { 
      do { 
       if let bookData = try JSONSerialization.jsonObject(with: data!) as? [[String:String]] { 
        books.removeAll() // clear data source array 
        for book in bookData { 
         let title = book["title"] ?? "" 
         let author = book["author"] ?? "" 
         let imgURL = book["imageURL"] ?? "" 
         books.append(Potter(title: title, author: author, imageURL: imgURL)) 
        } 
        DispatchQueue.main.async { 
         self.tableView.reloadData() 
        } 
       } 
      } 
      catch { 
       print("Serialization error", error) 
      } 
     } 

    } 
    task.resume() 
} 

有兩點需要注意:

  • 標準JSON字典斯威夫特3 [String:Any],在這種特殊情況下,它甚至[String:String]
  • .mutableContainers如果容器僅在Swift中被讀取和無用,無用,因爲該對象不能被鑄造到NSMutableArray/-Dictionary,並且使用var可以免費獲得可變性。
+1

@vadian ...可靠的答案,但要讓這個可憐的傢伙容易。他只是要求學習:) –

+0

@UnisBarakat是的,但他會學習錯誤的東西。 – vadian

+0

我的意思是不需要苛刻的語言「例如:瘋狂,懶惰,等等。」但這並不是什麼大不了的。 :) –

1

的方法downloadJSON()應在ViewController實施因爲它正在返回Potter數據的數組。然後在URLSession響應中,您應該創建一個數組,它將充當tableview數據源。 (即self.arrTableData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as? [[String : AnyObject]]

然後在用於的tableView

func tableView(_ tableView: UITableView, numberOfRowsInSection sectionIndex: Int) -> Int { 

     return self.arrTableData.count 
} 

並在索引通路單元用於行

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    //create `potters` object with the value and use it else you can direcly use the value of objects as below. 
    let dictPotters = self.arrTableData[indexPath.row] 
     let title = dictPotters["title"] 
    } 

由於

2
  1. 的web服務返回的數組對象:[Dictionary<String, AnyObject>]

  2. 如果使用字典作爲參數創建init方法將會更容易。

  3. downloadJSON是一個異步任務,使用completionHandler是最好的方法。如果您想將downloadJSON放置在Potter類中,則它應該是static函數。

  4. 最後,你應該處理的結果是這樣的:

    Potter.downloadJSON { potters in 
    
        self.potters = potters 
    
        DispatchQueue.main.async { 
         self.tableView.reloadData() 
        } 
    } 
    

最終代碼:

class ViewController: UIViewController { 

    var potters = [Potter]() 

    @IBOutlet weak var tableView: UITableView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     Potter.downloadJSON { potters in 

      self.potters = potters 

      DispatchQueue.main.async { 

       self.tableView.reloadData() 
      } 
     } 
    } 
} 

extension ViewController: UITableViewDelegate, UITableViewDataSource { 

    func numberOfSections(in tableView: UITableView) -> Int { 
     return 1 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return potters.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")! 

     let potter = potters[indexPath.row] 
     cell.textLabel?.text = potter.title 
     cell.detailTextLabel?.text = potter.author 

     return cell 
    } 
} 

class Potter { 

    private var _title: String! 
    private var _author: String! 
    private var _imageURL: String! 

    static let POTTER_URL = "http://de-coding-test.s3.amazonaws.com/books.json" 

    var title: String { 
     if _title == nil { 
      _title = "" 
     } 
     return _title 
    } 

    var author: String { 
     if _author == nil { 
      _author = "" 
     } 
     return _author 
    } 

    var imageURL: String { 
     if _imageURL == nil { 
      _imageURL = "" 
     } 
     return _imageURL 
    } 

    init(dict: Dictionary<String, AnyObject>) { 
     self._title = dict["title"] as? String 
     self._imageURL = dict["imageURL"] as? String 
     self._author = dict["author"] as? String 
    } 

    class func downloadJSON(completion: @escaping (_ potters: [Potter]) -> Void) { 

     let url = URL(string: POTTER_URL) 
     let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in 

      if error != nil { 
       print("Error") 

      } else { 

       if let content = data { 

        do { 
         if let jArray = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as? [Dictionary<String, AnyObject>] { 

          var potters = [Potter]() 
          for jDict in jArray { 
           let potter = Potter(dict: jDict) 
           potters.append(potter) 
          } 
          completion(potters) 
         } 
        } 
        catch { 
        } 
       } 
      } 
     } 
     task.resume() 
    } 
} 

enter image description here