如何将字符串数据从 API POST 请求传递到另一个 ViewController
How to pass String data from API POST request to another ViewController
我绝对是 Swift 和编程的初学者。
我不知道如何将调用 POST 请求的函数的响应传递到第二个视图控制器上的文本标签。我认为这可能是主线程有问题,但我不知道如何解决。我真的尝试寻找解决方案,但对我没有任何帮助。
这是我的函数:
func getBookTitle() -> String {
var bookTitle = ""
if let bookNameURL = URL(string: urlString) {
do {
let htmlString = try String(contentsOf: bookNameURL, encoding: .utf8)
let htmlContent = htmlString
do {
let doc = try SwiftSoup.parse(htmlContent)
do {
let bookNumber = try doc.select("a.dlink").attr("onclick")
let bookNumberTrim = bookNumber.trimmingCharacters(in: CharacterSet.decimalDigits.inverted).components(separatedBy: ",")
do {
let bookid = bookNumberTrim[0]
let passageid = bookNumberTrim[1]
print(bookid)
print(passageid)
//Get Book Title
let url:URL = URL(string: "\(urlString)/getname")!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "bookid=\(bookid)&passageid=\(passageid)"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
do {
let doc: Document = try SwiftSoup.parse(dataString ?? "")
do {
let bTitle = try doc.select("div").first()
bookTitle = try bTitle!.text()
print(bookTitle)
}
} catch {
print(error)
}
}
task.resume()
}
} catch {
print(error)
}
}
} catch let error {
print("Error \(error)")
}
} else {
print("Something wrong")
}
return bookTitle
}
这就是我试图将数据传递给另一个人的方式VC:
@IBAction func infoButtonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToInfo", sender: sender)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToInfo" {
let destinationVC = segue.destination as! BookInfoVC
destinationVC.bookName = networkService.getBookTitle()
}
}
第二个VC:
class BookInfoVC: UIViewController {
@IBOutlet weak var bookTitle: UILabel!
var bookName: String!
override func viewDidLoad() {
super.viewDidLoad()
bookTitle.text = bookName
}
}
函数的响应是一行字符串。
非常感谢!
更新:
我试图在我的函数中实现完成处理程序,现在它看起来像这样:
func getBookTitle(completion: @escaping (String) -> ()) {
if let bookNameURL = URL(string: urlString) {
do {
let htmlString = try String(contentsOf: bookNameURL, encoding: .utf8)
let htmlContent = htmlString
do {
let doc = try SwiftSoup.parse(htmlContent)
do {
let bookNumber = try doc.select("a.dlink").attr("onclick")
let bookNumberTrim = bookNumber.trimmingCharacters(in: CharacterSet.decimalDigits.inverted).components(separatedBy: ",")
do {
let bookid = bookNumberTrim[0]
let passageid = bookNumberTrim[1]
//MARK: - Fetch book title
let params = BookTitle(bookid: bookid, passageid: passageid)
AF.request("\(self.urlString)/getname", method: .post, parameters: params).validate(contentType: ["application/x-www-form-urlencoded"]).response { (response) in
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
do {
let html: String = utf8Text
let doc: Document = try SwiftSoup.parse(html)
do {
let parseTitle = try doc.select("div").first()
let bookTitle = try parseTitle!.text()
completion(bookTitle)
} catch {
print(error)
}
} catch {
print(error)
}
}
}
}
} catch {
print(error)
}
}
} catch let error {
print("Error \(error)")
}
} else {
print("Something wrong")
}
}
我这样称呼它:
@IBAction func infoButtonPressed(_ sender: UIButton) {
self.performSegue(withIdentifier: "goToInfo", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToInfo" {
let destinationVC = segue.destination as! BookInfoVC
networkService.getBookTitle { bookTitle in
destinationVC.bookName = bookTitle
print(bookTitle)
}
}
我已经尝试将 DispatchQueue.main.async 粘贴到各处,但它仍然没有更新第二个 VC 上的文本标签。但是在主视图控制器中,它工作正常。
简答:你不能。您正在发出异步请求。该函数将 return 在结果可用之前。您需要重写您的函数以获取完成处理程序。当结果可用时,您将调用完成处理程序。这在这个版块上被广泛讨论。
编辑:
您更新后的 getBookTitle(completion:)
函数看起来不错,但现在您遇到了排序问题。
您的第一个视图控制器中的 prepare(for segue:)
方法使用您的 networkService.getBookTitle(completion:)
函数,并在完成处理程序中设置 destinationVC.bookName
.
但是,请记住 networkService.getBookTitle(completion:)
是异步运行的。它 return 立即等待网络结果,然后 然后 调用完成处理程序。
您的目标视图控制器(BookInfoVC
类型)尝试在其 viewDidLoad
方法中将 bookName
安装到其 UI 中。 viewDidLoad()
在第一个视图控制器的 prepare(for segue:)
触发后立即被调用。在调用 viewDidLoad 时,bookName
很可能仍然是 nil。
您需要在 BookInfoVC
的 bookName
属性 上添加一个 didSet 方法,以便它响应书名的更改。这可能看起来像这样:
var bookName: String! {
didSet: {
bookTitle.text = bookName
}
}
如果您这样做,当 getBookTitle() 的完成处理程序触发时,它将更改 destinationVC.bookName
。这将导致 BookInfoVC
的 bookName
didSet
代码被触发,将更新后的 bookName
安装到 UI.
我绝对是 Swift 和编程的初学者。
我不知道如何将调用 POST 请求的函数的响应传递到第二个视图控制器上的文本标签。我认为这可能是主线程有问题,但我不知道如何解决。我真的尝试寻找解决方案,但对我没有任何帮助。
这是我的函数:
func getBookTitle() -> String {
var bookTitle = ""
if let bookNameURL = URL(string: urlString) {
do {
let htmlString = try String(contentsOf: bookNameURL, encoding: .utf8)
let htmlContent = htmlString
do {
let doc = try SwiftSoup.parse(htmlContent)
do {
let bookNumber = try doc.select("a.dlink").attr("onclick")
let bookNumberTrim = bookNumber.trimmingCharacters(in: CharacterSet.decimalDigits.inverted).components(separatedBy: ",")
do {
let bookid = bookNumberTrim[0]
let passageid = bookNumberTrim[1]
print(bookid)
print(passageid)
//Get Book Title
let url:URL = URL(string: "\(urlString)/getname")!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "bookid=\(bookid)&passageid=\(passageid)"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
do {
let doc: Document = try SwiftSoup.parse(dataString ?? "")
do {
let bTitle = try doc.select("div").first()
bookTitle = try bTitle!.text()
print(bookTitle)
}
} catch {
print(error)
}
}
task.resume()
}
} catch {
print(error)
}
}
} catch let error {
print("Error \(error)")
}
} else {
print("Something wrong")
}
return bookTitle
}
这就是我试图将数据传递给另一个人的方式VC:
@IBAction func infoButtonPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToInfo", sender: sender)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToInfo" {
let destinationVC = segue.destination as! BookInfoVC
destinationVC.bookName = networkService.getBookTitle()
}
}
第二个VC:
class BookInfoVC: UIViewController {
@IBOutlet weak var bookTitle: UILabel!
var bookName: String!
override func viewDidLoad() {
super.viewDidLoad()
bookTitle.text = bookName
}
}
函数的响应是一行字符串。
非常感谢!
更新: 我试图在我的函数中实现完成处理程序,现在它看起来像这样:
func getBookTitle(completion: @escaping (String) -> ()) {
if let bookNameURL = URL(string: urlString) {
do {
let htmlString = try String(contentsOf: bookNameURL, encoding: .utf8)
let htmlContent = htmlString
do {
let doc = try SwiftSoup.parse(htmlContent)
do {
let bookNumber = try doc.select("a.dlink").attr("onclick")
let bookNumberTrim = bookNumber.trimmingCharacters(in: CharacterSet.decimalDigits.inverted).components(separatedBy: ",")
do {
let bookid = bookNumberTrim[0]
let passageid = bookNumberTrim[1]
//MARK: - Fetch book title
let params = BookTitle(bookid: bookid, passageid: passageid)
AF.request("\(self.urlString)/getname", method: .post, parameters: params).validate(contentType: ["application/x-www-form-urlencoded"]).response { (response) in
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
do {
let html: String = utf8Text
let doc: Document = try SwiftSoup.parse(html)
do {
let parseTitle = try doc.select("div").first()
let bookTitle = try parseTitle!.text()
completion(bookTitle)
} catch {
print(error)
}
} catch {
print(error)
}
}
}
}
} catch {
print(error)
}
}
} catch let error {
print("Error \(error)")
}
} else {
print("Something wrong")
}
}
我这样称呼它:
@IBAction func infoButtonPressed(_ sender: UIButton) {
self.performSegue(withIdentifier: "goToInfo", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToInfo" {
let destinationVC = segue.destination as! BookInfoVC
networkService.getBookTitle { bookTitle in
destinationVC.bookName = bookTitle
print(bookTitle)
}
}
我已经尝试将 DispatchQueue.main.async 粘贴到各处,但它仍然没有更新第二个 VC 上的文本标签。但是在主视图控制器中,它工作正常。
简答:你不能。您正在发出异步请求。该函数将 return 在结果可用之前。您需要重写您的函数以获取完成处理程序。当结果可用时,您将调用完成处理程序。这在这个版块上被广泛讨论。
编辑:
您更新后的 getBookTitle(completion:)
函数看起来不错,但现在您遇到了排序问题。
您的第一个视图控制器中的 prepare(for segue:)
方法使用您的 networkService.getBookTitle(completion:)
函数,并在完成处理程序中设置 destinationVC.bookName
.
但是,请记住 networkService.getBookTitle(completion:)
是异步运行的。它 return 立即等待网络结果,然后 然后 调用完成处理程序。
您的目标视图控制器(BookInfoVC
类型)尝试在其 viewDidLoad
方法中将 bookName
安装到其 UI 中。 viewDidLoad()
在第一个视图控制器的 prepare(for segue:)
触发后立即被调用。在调用 viewDidLoad 时,bookName
很可能仍然是 nil。
您需要在 BookInfoVC
的 bookName
属性 上添加一个 didSet 方法,以便它响应书名的更改。这可能看起来像这样:
var bookName: String! {
didSet: {
bookTitle.text = bookName
}
}
如果您这样做,当 getBookTitle() 的完成处理程序触发时,它将更改 destinationVC.bookName
。这将导致 BookInfoVC
的 bookName
didSet
代码被触发,将更新后的 bookName
安装到 UI.