Swift 3使用URLSession将JSON解析为UITableView
我想使用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]()
的属性,以及如何建立合适的穿线
所有模型首先是
疯狂
很奇怪。
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
可以免费获得可变性。
的方法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"]
}
由于
的web服务返回的数组对象:
[Dictionary<String, AnyObject>]
。如果使用字典作为参数创建
init
方法将会更容易。downloadJSON
是一个异步任务,使用completionHandler
是最好的方法。如果您想将downloadJSON
放置在Potter
类中,则它应该是static
函数。-
最后,你应该处理的结果是这样的:
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()
}
}
@vadian ...可靠的答案,但要让这个可怜的家伙容易。他只是要求学习:) –
@UnisBarakat是的,但他会学习错误的东西。 – vadian
我的意思是不需要苛刻的语言“例如:疯狂,懒惰,等等。”但这并不是什么大不了的。 :) –