在Swift中使用HTTP Post请求“刷新”应用程序?

时间:2016-11-15 02:57:21

标签: ios json swift

我正在创建一个应用程序来解析学生信息的SQL数据库并以JSON格式返回数据。它有一个学生名称的TableView,当你点击一个名字时,它会带你到另一个有更多信息的ViewController。获得数据后,我希望用户能够在应用程序中编辑它,这是通过HTTP Post请求完成的。

然而,一旦Post请求成功,我就无法弄清楚如何“刷新”或重新加载应用程序以便显示新的/更新的数据。截至目前,我必须重新启动应用程序,以便更改显示在TableView和“更多信息”ViewController中(例如,如果我将学生的名字从“Bob”更改为“Joe”,它将会仍然会说“鲍勃”,直到下次我运行应用程序)。我有很多代码,所以我会尝试只发布重要的部分:

HandleData.swift(发生JSON解析等)

func downloadItems() {
    let url:URL = URL(string: urlAddress)!
    var urlSession:Foundation.URLSession!
    let config = URLSessionConfiguration.default

    urlSession = Foundation.URLSession(configuration: config, delegate: self, delegateQueue: nil)
    let task = urlSession.dataTask(with: url)
    task.resume()
}

func URLSession(_ session: Foundation.URLSession, dataTask: URLSessionDataTask, didReceiveData data: Data) {
    self.data.append(data);
}

func URLSession(_ session: Foundation.URLSession, task: URLSessionTask, didCompleteWithError error: NSError?) {
    if error != nil {
        print("Download of data failed.")
    }
    else {
        print("Data downloaded successfully!")
        self.parseJSON()
    }
}

func parseJSON() {
    var jsonResult:NSMutableArray = NSMutableArray()
    do {
        jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSMutableArray
    }
    catch let error as NSError {
        print(error)
    }

    var jsonElement:NSDictionary = NSDictionary()
    let locations:NSMutableArray = NSMutableArray()

    for i in 0 ..< jsonResult.count {
        jsonElement = jsonResult[i] as! NSDictionary
        let location = StoreData()

        let studentID = jsonElement["StudentId"] as? String
            let lastName = jsonElement["LastName"] as? String
            let firstName = jsonElement["FirstName"] as? String
            let major = jsonElement["Major"] as? String
            let year = jsonElement["Year"] as? String
            let gpa = jsonElement["GPA"] as? Double
            location.studentID = studentID
            location.lastName = lastName
            location.firstName = firstName
            location.major = major
            location.year = year
            location.gpa = gpa

        locations.add(location)
    }
    DispatchQueue.main.async(execute: { () -> Void in
        self.delegate.itemsDownloaded(locations)
    })
}

DetailViewController.swift(“更多信息”屏幕)

func editData() {
    var request = URLRequest(url: URL(string: "http://csmadison.dhcp.bsu.edu/~vjtanksale/cs320/updatestudents.php")!)
    request.httpMethod = "POST"
    let postString = "StudentId=\(idTB.text!)&FirstName=\(nameTB.text!)&LastName=\(lastNameTB.text!)&Major=\(majorTB.text!)&Year=\(yearTB.text!)&GPA=\(gpaTB.text!)"
    request.httpBody = postString.data(using: .utf8)
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print("Error = \(error)")
            return
        }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
            print("The status code is \(httpStatus.statusCode)")
            print("Response = \(response)")
        }

        let responseString = String(data: data, encoding: .utf8)
        print("Response String = \(responseString!)")
    }
    task.resume()
}

//Below is the function for the "Done" button that the user taps when they're finished editing a particular student's information

@IBAction func donePressed(_ sender: Any) {
    editData()
}

ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, HandleDataProtocol {
var studentItems:NSArray = NSArray()
var storeData:StoreData = StoreData()
var handleData = HandleData()
@IBOutlet var studentsTable: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    self.studentsTable.delegate = self
    self.studentsTable.dataSource = self
    handleData = HandleData()
    handleData.delegate = self
    handleData.downloadItems()
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func itemsDownloaded(_ items: NSArray) {
    studentItems = items
    self.studentsTable.reloadData()
}

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

1 个答案:

答案 0 :(得分:1)

您可以使用UITableView重新加载整个reloadRowsAtIndexPaths或仅重新加载所需的单元格。

到目前为止,我在您的代码中看到,您在请求完成时使用委托模式进行通知,请记住您也可以使用闭包来实现此目的。如果您未将代理引用声明为weak,则需要谨慎使用委托并保留周期。

正如@ Tj3n在他的评论中指出的那样,正常的过程应该是在你使用CoreData,Realm,Firebase,MySQL或其他你想要的一些持久层中保存来自API的数据(NSUserDefaults不适用于当你发出另一个更改数据的请求时,如果你在持久层中保存了数据,你需要通知每个人正在使用你的模型来更改数据。

如果您不想使用上面提到的任何库来通知模型中的更改,您可以使用委托,KVO或使用NSNotificationCenter的观察者模式。尽管如此,Firebase和Realm可以很容易地为您实现有关模型更改的通知。

来自LinkedIn和Pinterest的这两篇文章展示了如何使用不可变模型处理它的非常好的解释。

我强烈建议您使用的另一件事是在某些服务中隔离您的请求,从而删除DetailViewController中的依赖项。这使您的代码更难以测试。

我的解释缺乏示例代码,但我想你会发现很多关于如何在网络中使用CoreData,Realm,Firebase以及在SO中使用的示例。

我希望这对你有所帮助。