如何在 Swift 中正确实现不同视图控制器之间的协议和委托?
How to properly implement protocols and delegates between different view controllers in Swift?
所以我是协议和委托的新手。但是,在了解它之后,我尝试在我的项目中使用它。我不确定我是否做错了什么。但我无法更新标签。
import UIKit
class CountryVC: UIViewController {
//MARK:-Properties
let deathLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
label.text = "I am Death"
return label
}()
let recoveredLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
return label
}()
let infectedLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(deathsView)
view.addSubview(infectedView)
view.addSubview(recoveredView)
deathsView.anchor(top: view.topAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 100, paddingLeft: 20, paddingRight: 20, height: 100)
deathsView.addSubview(deathLabel)
deathLabel.anchor()
deathLabel.centerXAnchor.constraint(equalTo: deathsView.centerXAnchor).isActive = true
deathLabel.centerYAnchor.constraint(equalTo: deathsView.centerYAnchor).isActive = true
infectedView.anchor(top: deathsView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 20, paddingLeft: 20, paddingRight: 20, height: 100)
deathsView.addSubview(infectedLabel)
infectedLabel.anchor()
infectedLabel.centerXAnchor.constraint(equalTo: infectedView.centerXAnchor).isActive = true
infectedLabel.centerYAnchor.constraint(equalTo: infectedView.centerYAnchor).isActive = true
recoveredView.anchor(top: infectedView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 20, paddingLeft: 20, paddingRight: 20, height: 100)
recoveredView.addSubview(recoveredLabel)
recoveredLabel.anchor()
recoveredLabel.centerXAnchor.constraint(equalTo: recoveredView.centerXAnchor).isActive = true
recoveredLabel.centerYAnchor.constraint(equalTo: recoveredView.centerYAnchor).isActive = true
}
}
extension CountryVC: UpdateCountry {
func update(allCases: Int, recovered: Int, deaths: Int) {
DispatchQueue.main.async {
self.deathLabel.text = String(deaths)
self.recoveredLabel.text = String(recovered)
self.infectedLabel.text = String(allCases)
}
print (String(deaths))
print(String(recovered))
print(String(allCases))
}
}
我可以看到数据通过,因为我可以打印数据。我在我的另一个 table 视图控制器中调用了更新函数来获取这样的数据。
class CountryTableControllerTableViewController: UITableViewController {
//MARK:- Properties
var delegate: UpdateCountry!
//MARK:- Initialization
override func viewDidLoad() {
super.viewDidLoad()
delegate = CountryVC()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier")
self.navigationItem.title = "Select Your Country"
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int { 1 }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { countries.count }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = countries[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let urlCountry = "https://corona.lmao.ninja/countries/\(countries[indexPath.row])"
let acturalUrl = urlCountry.lowercased()
guard let url = URL(string: acturalUrl) else { return }
let controler = CountryVC()
controler.modalPresentationStyle = .fullScreen
present(controler, animated: true, completion: nil)
URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {return}
do {
let allCases = try JSONDecoder().decode(CountryCases.self, from: data)
self.delegate.update(allCases: allCases.cases, recovered: allCases.recovered, deaths: allCases.deaths)
} catch let jsonErr {
print("Error serializing json", jsonErr)
}
}.resume()
}
}
控制器已显示数据,但标签未在 countryVC 中更新。
首先按如下方式创建协议:
protocol CountryViewControllerDelegate: class {
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int)
}
然后在您的 CountryViewController 中:
class CountryViewController: UIViewController {
weak var delegate: CountryViewControllerDelegate?
// code ...
}
extension CountryViewController: CountryViewControllerDelegate {
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int) {
print("CountryViewController:", #function)
DispatchQueue.main.async {
// update your labels in the main thread
// self.deathLabel.text = String(deaths)
// self.recoveredLabel.text = String(recovered)
// self.infectedLabel.text = String(allCases)
print("Country:", country)
print("deaths:", deaths)
print("recovered:", recovered)
print("infected:", allCases)
}
}
}
终于在您的 CountryTableViewController 中:
class CountryTableViewController: UITableViewController, CountryViewControllerDelegate {
weak var delegate: CountryViewControllerDelegate?
// code ...
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Select Your Country"
delegate = self
}
// code ...
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let country = countries[indexPath.row]
let string = "https://corona.lmao.ninja/countries/\(country.lowercased())"
guard let url = URL(string: link) else { return }
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyBoard.instantiateViewController(withIdentifier: "CountryViewController") as! CountryViewController
controller.delegate = self
controller.modalPresentationStyle = .pageSheet
controller.title = country
let countryNavigationController = UINavigationController(rootViewController: controller)
countryNavigationController.viewControllers = [controller]
self.present(countryNavigationController, animated: true)
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
if let string = String(data: data, encoding: .utf8), string == "Country not found" {
self.updateLabels(controller, country: country, allCases: 0, recovered: 0, deaths: 0)
return
}
do {
let allCases = try JSONDecoder().decode(CountryCases.self, from: data)
self.updateLabels(controller, country: country, allCases: allCases.cases, recovered: allCases.recovered, deaths: allCases.deaths)
} catch {
print("JSON error:", error)
}
}.resume()
}
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int) {
print("CountryTableViewController:", #function)
controller.updateLabels(controller, country: country, allCases: allCases, recovered: recovered, deaths: deaths)
}
}
所以我是协议和委托的新手。但是,在了解它之后,我尝试在我的项目中使用它。我不确定我是否做错了什么。但我无法更新标签。
import UIKit
class CountryVC: UIViewController {
//MARK:-Properties
let deathLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
label.text = "I am Death"
return label
}()
let recoveredLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
return label
}()
let infectedLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(deathsView)
view.addSubview(infectedView)
view.addSubview(recoveredView)
deathsView.anchor(top: view.topAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 100, paddingLeft: 20, paddingRight: 20, height: 100)
deathsView.addSubview(deathLabel)
deathLabel.anchor()
deathLabel.centerXAnchor.constraint(equalTo: deathsView.centerXAnchor).isActive = true
deathLabel.centerYAnchor.constraint(equalTo: deathsView.centerYAnchor).isActive = true
infectedView.anchor(top: deathsView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 20, paddingLeft: 20, paddingRight: 20, height: 100)
deathsView.addSubview(infectedLabel)
infectedLabel.anchor()
infectedLabel.centerXAnchor.constraint(equalTo: infectedView.centerXAnchor).isActive = true
infectedLabel.centerYAnchor.constraint(equalTo: infectedView.centerYAnchor).isActive = true
recoveredView.anchor(top: infectedView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 20, paddingLeft: 20, paddingRight: 20, height: 100)
recoveredView.addSubview(recoveredLabel)
recoveredLabel.anchor()
recoveredLabel.centerXAnchor.constraint(equalTo: recoveredView.centerXAnchor).isActive = true
recoveredLabel.centerYAnchor.constraint(equalTo: recoveredView.centerYAnchor).isActive = true
}
}
extension CountryVC: UpdateCountry {
func update(allCases: Int, recovered: Int, deaths: Int) {
DispatchQueue.main.async {
self.deathLabel.text = String(deaths)
self.recoveredLabel.text = String(recovered)
self.infectedLabel.text = String(allCases)
}
print (String(deaths))
print(String(recovered))
print(String(allCases))
}
}
我可以看到数据通过,因为我可以打印数据。我在我的另一个 table 视图控制器中调用了更新函数来获取这样的数据。
class CountryTableControllerTableViewController: UITableViewController {
//MARK:- Properties
var delegate: UpdateCountry!
//MARK:- Initialization
override func viewDidLoad() {
super.viewDidLoad()
delegate = CountryVC()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier")
self.navigationItem.title = "Select Your Country"
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int { 1 }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { countries.count }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = countries[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let urlCountry = "https://corona.lmao.ninja/countries/\(countries[indexPath.row])"
let acturalUrl = urlCountry.lowercased()
guard let url = URL(string: acturalUrl) else { return }
let controler = CountryVC()
controler.modalPresentationStyle = .fullScreen
present(controler, animated: true, completion: nil)
URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {return}
do {
let allCases = try JSONDecoder().decode(CountryCases.self, from: data)
self.delegate.update(allCases: allCases.cases, recovered: allCases.recovered, deaths: allCases.deaths)
} catch let jsonErr {
print("Error serializing json", jsonErr)
}
}.resume()
}
}
控制器已显示数据,但标签未在 countryVC 中更新。
首先按如下方式创建协议:
protocol CountryViewControllerDelegate: class {
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int)
}
然后在您的 CountryViewController 中:
class CountryViewController: UIViewController {
weak var delegate: CountryViewControllerDelegate?
// code ...
}
extension CountryViewController: CountryViewControllerDelegate {
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int) {
print("CountryViewController:", #function)
DispatchQueue.main.async {
// update your labels in the main thread
// self.deathLabel.text = String(deaths)
// self.recoveredLabel.text = String(recovered)
// self.infectedLabel.text = String(allCases)
print("Country:", country)
print("deaths:", deaths)
print("recovered:", recovered)
print("infected:", allCases)
}
}
}
终于在您的 CountryTableViewController 中:
class CountryTableViewController: UITableViewController, CountryViewControllerDelegate {
weak var delegate: CountryViewControllerDelegate?
// code ...
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Select Your Country"
delegate = self
}
// code ...
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let country = countries[indexPath.row]
let string = "https://corona.lmao.ninja/countries/\(country.lowercased())"
guard let url = URL(string: link) else { return }
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyBoard.instantiateViewController(withIdentifier: "CountryViewController") as! CountryViewController
controller.delegate = self
controller.modalPresentationStyle = .pageSheet
controller.title = country
let countryNavigationController = UINavigationController(rootViewController: controller)
countryNavigationController.viewControllers = [controller]
self.present(countryNavigationController, animated: true)
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
if let string = String(data: data, encoding: .utf8), string == "Country not found" {
self.updateLabels(controller, country: country, allCases: 0, recovered: 0, deaths: 0)
return
}
do {
let allCases = try JSONDecoder().decode(CountryCases.self, from: data)
self.updateLabels(controller, country: country, allCases: allCases.cases, recovered: allCases.recovered, deaths: allCases.deaths)
} catch {
print("JSON error:", error)
}
}.resume()
}
func updateLabels(_ controller: CountryViewController, country: String, allCases: Int, recovered: Int, deaths: Int) {
print("CountryTableViewController:", #function)
controller.updateLabels(controller, country: country, allCases: allCases, recovered: recovered, deaths: deaths)
}
}