我对 swift 编程很陌生,对 Web 服务也不是很熟悉。我想为诗歌创建一个iOS移动应用程序。
我能够检索 json 编码的数据,但我的问题是我无法将其传输到我的表视图。当我运行它时,我认为问题是由于异步任务。由于它位于异步任务中,因此当 name.count 仍为 0 时,将执行表视图 (numberOfRows( 的委托函数,因为该任务将在执行委托的 func 后运行。这就是为什么我无法在表格视图中看到我的数据...我希望有人能在这里帮助我。我已经用谷歌搜索并尝试了完成处理程序(我不知道它的用途(,我尝试将其更改为同步,这导致我出错。谢谢!!!
import UIKit
import Foundation
class TimelineViewController: UIViewController {
@IBOutlet weak var contentTableView: UITableView!
var name = [String]()
var bio = [String]()
@IBOutlet weak var oPostBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
getPoems()
}
func getPoems()
{
let url:NSURL = NSURL(string: "http://192.168.1.6/Test/feed1.php")!
let request:NSMutableURLRequest = NSMutableURLRequest(url:url as URL)
request.httpMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main){(response, data, error) in }
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("Error = (error)")
return
}
do {
print("Response=(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Response data = (responseString)")
//Converting response to NSDictionary
var json: NSDictionary!
json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
//getting the JSONArray poems from the response
let returnPoems: NSArray = json["returnPoems"] as! NSArray
print(returnPoems);
//looping through all the json objects in the array teams
for i in 0 ..< returnPoems.count{
let aObject = returnPoems[i] as! [String : AnyObject]
self.name.append(aObject["fullName"] as! String)
self.bio.append(aObject["Bio"] as! String)
//displaying the data
print("Fullname -> ", self.name)
print("Bio ->", self.bio)
print("===================")
print("")
}
}
catch {
print("ERROR: (error)")
}
}
task.resume()
}
}
extension TimelineViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = contentTableView.dequeueReusableCell(withIdentifier: "PoemCell")
cell?.textLabel?.text = name[indexPath.row]
cell?.detailTextLabel?.text = bio[indexPath.row]
return cell!
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return name.count
}
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #(indexPath.row)!")
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
}
}
在完成块中,构建完name
数组并bio
数组后,通过从主队列调用reloadData
来刷新表:
DispatchQueue.main.async {
self.tableView.reloadData()
}
我还有其他一些建议:
您应该删除该
NSURLConnection
代码。它正在执行冗余请求,而您没有对响应执行任何操作;另外,无论如何它都是一个已弃用的 API,应该删除;你应该使用
URL
而不是NSURL
;你应该使用
URLRequest
而不是NSMutableURLRequest
;你应该使用
String
而不是NSString
;你应该使用 Swift
Array
和Dictionary
而不是NSArray
和NSDictionary
;您的
didSelectRowAt
签名不正确。使用IndexPath
,而不是NSIndexPath
。您正在从
URLSession
后台队列更新name
和bio
数组。这不是线程安全的。您可以通过从主队列更新这些来解决此问题,以避免需要执行额外的同步。我什至建议摆脱这两个不同的数组,并拥有一个自定义对象的数组,
Poem
.这使得代码更简单。它也开辟了新的可能性(例如,如果您想对name
数组进行排序怎么办......您将如何相应地更新单独的bio
数组;使用单个自定义对象,此问题就会消失(。
因此:
struct Poem {
let name: String
let bio: String
init?(dictionary: [String: Any]) {
guard let name = dictionary["fullName"] as? String,
let bio = dictionary["Bio"] as? String else {
print("Did not find fullName/Bio")
return nil
}
self.name = name
self.bio = bio
}
}
class TimelineViewController: UIViewController {
@IBOutlet weak var contentTableView: UITableView!
var poems = [Poem]()
@IBOutlet weak var oPostBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
getPoems()
}
func getPoems() {
let url = URL(string: "http://192.168.1.6/Test/feed1.php")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("Error = (error?.localizedDescription ?? "Unknown error")")
return
}
if let response = response {
print("Response=(response)")
}
if let responseString = String(data: data, encoding: .utf8) {
print("Response data = (responseString)")
}
// Converting response to Dictionary
guard let json = try? JSONSerialization.jsonObject(with: data),
let responseObject = json as? [String: Any],
let returnPoems = responseObject["returnPoems"] as? [[String: Any]] else {
print("did not find returnPoems")
return
}
print(returnPoems)
// dispatch the update of model and UI to the main queue
DispatchQueue.main.async {
self.poems = returnPoems.flatMap { Poem(dictionary: $0) }
self.contentTableView.reloadData()
}
}
task.resume()
}
}
extension TimelineViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = contentTableView.dequeueReusableCell(withIdentifier: "PoemCell", for: indexPath)
let poem = poems[indexPath.row]
cell.textLabel?.text = poem.name
cell.detailTextLabel?.text = poem.bio
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return poems.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #(indexPath.row)!")
// let indexPath = tableView.indexPathForSelectedRow! // why do this? ... the indexPath was passed to this function
// let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell // why do this? ... you don't care about the cell ... go back to you model
let poem = poems[indexPath.row]
// do something with poem, e.g.
print(poem)
}
}