Swift 3 使用 URLSession 将 JSON 解析为 UITableView
Swift 3 Parse JSON into UITableView using URLSession
我正在尝试使用 URLSession 解析 JSON,而不使用 Alamofire 或其他任何东西。
我只想将 JSON 放入 UITableView。
我正在尝试将我从学习如何使用 Alamofire 解析 JSON 中学到的东西与我在 google 上可以找到的东西拼凑起来。 youtube 或 Stack 等上的许多答案都使用 NS..NSURL、NSDictionary 等..或者只是键入代码而不解释 what/why.
我想我快到了,但我需要帮助来理解我剩下要做的事情。
所以。
我允许在 plst 中任意加载
在 Swift 文件中,我有以下内容
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 中,我添加了表格视图并设置了所有 UI,在我的 ViewController 中,我设置了表格视图委托。
我创建了 属性 个
var potters = [Potter]()
我现在不知道如何填充这个数组,以及如何设置正确的线程
方法 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"]
}
谢谢
网络服务returns对象数组:[Dictionary<String, AnyObject>]
.
如果您创建一个以字典作为参数的init
方法会更容易。
downloadJSON
是一个异步任务,使用completionHandler
是最好的方式。而如果要将downloadJSON
放在Potter
class中,应该是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()
}
}
首先你的模型疯狂很奇怪。
在 Swift 中 从不 使用受支持的私有变量来获取 read/only 属性。 从不 将属性声明为隐式解包可选,因为你懒得写初始化程序。
整个模型可以缩减为
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
项目并将其附加到数据源。如果值不存在,则分配一个空字符串。最后在主线程上重新加载 table 视图。
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()
}
两个注意事项:
- Swift 3 中的标准 JSON 字典是
[String:Any]
,在这种特殊情况下它甚至是 [String:String]
。
.mutableContainers
如果容器只被读取并且在 Swift 中无用,那么 .mutableContainers
是无用的,因为对象不能被转换为 NSMutableArray / -Dictionary
并且你可以使用 [=25 免费获得可变性=]iable.
我正在尝试使用 URLSession 解析 JSON,而不使用 Alamofire 或其他任何东西。
我只想将 JSON 放入 UITableView。
我正在尝试将我从学习如何使用 Alamofire 解析 JSON 中学到的东西与我在 google 上可以找到的东西拼凑起来。 youtube 或 Stack 等上的许多答案都使用 NS..NSURL、NSDictionary 等..或者只是键入代码而不解释 what/why.
我想我快到了,但我需要帮助来理解我剩下要做的事情。
所以。
我允许在 plst 中任意加载
在 Swift 文件中,我有以下内容
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 中,我添加了表格视图并设置了所有 UI,在我的 ViewController 中,我设置了表格视图委托。
我创建了 属性 个
var potters = [Potter]()
我现在不知道如何填充这个数组,以及如何设置正确的线程
方法 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"]
}
谢谢
网络服务returns对象数组:
[Dictionary<String, AnyObject>]
.如果您创建一个以字典作为参数的
init
方法会更容易。downloadJSON
是一个异步任务,使用completionHandler
是最好的方式。而如果要将downloadJSON
放在Potter
class中,应该是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()
}
}
首先你的模型疯狂很奇怪。
在 Swift 中 从不 使用受支持的私有变量来获取 read/only 属性。 从不 将属性声明为隐式解包可选,因为你懒得写初始化程序。
整个模型可以缩减为
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
项目并将其附加到数据源。如果值不存在,则分配一个空字符串。最后在主线程上重新加载 table 视图。
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()
}
两个注意事项:
- Swift 3 中的标准 JSON 字典是
[String:Any]
,在这种特殊情况下它甚至是[String:String]
。 .mutableContainers
如果容器只被读取并且在 Swift 中无用,那么.mutableContainers
是无用的,因为对象不能被转换为NSMutableArray / -Dictionary
并且你可以使用 [=25 免费获得可变性=]iable.