我正在按照本教程使用闭包发回数据。 https://betterprogramming.pub/5-ways-to-pass-data-between-view-controllers-18acb467f5ec
在本教程中,第 4 点是“闭包”。我有两个 VC,一个用于选择宠物(FormsVC),一个用于显示所选宠物(ProfileVC)。
下面是ProfileVC的代码:
// ProfileVC
// MARK: - Set Fav Pet Name
func setPetName(pet: String) {
lblFavouritePet.text = pet
}
// MARK: - Button Select Your Fav Pet Event
@IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
self.present(vc, animated: true)
}
下面是FormsVC的代码:
// FormsVC
// MARK: - Variable Declaration
var favoritePet = String()
// MARK: - viewDidLoad Method
override func viewDidLoad() {
super.viewDidLoad()
setUpFormsVC()
}
// MARK: - Set Up FormsVC
func setUpFormsVC() {
btnDog.titleLabel?.text = "Dog"
btnCat.titleLabel?.text = "Cat"
btnRabbit.titleLabel?.text = "Rabbit"
btnBird.titleLabel?.text = "Bird"
}
// MARK: - Button Selected Pet Event
@IBAction func selectedPetEvent(_ sender: UIButton) {
favoritePet = sender.titleLabel?.text ?? "Dog"
}
// MARK: - Selected Pet Name
func getFavoritePet() -> String {
return favoritePet
}
// MARK: - Button OK Event
@IBAction func btnOk_Event(_ sender: UIButton) {
let vc = ProfileVC()
self.dismiss(animated: true, completion: {
vc.setPetName(pet: self.getFavoritePet())
})
// problem occurs when I dismiss FormsVC after selecting pet, the label displaying selected pet name (lblFavouritePet) throwing error of "Unexpectedly found nil while implicitly unwrapping an Optional value"
}
}
当我在选择宠物后关闭 FormsVC 时出现问题,显示所选宠物名称 (lblFavouritePet) 的标签抛出错误“隐式展开可选值时意外发现 nil”。我不知道为什么它被发现为零,因为我已经分配了 favoritePet 的所选宠物的价值。抱歉这个愚蠢的问题,有人能帮我吗?
首先,你必须声明越近你想传递数据的地方。
// FormsVC
// MARK: - Variable Declaration
let completion: ((String)->Void)? = nil
// MARK: - Button OK Event
@IBAction func btnOk_Event(_ sender: UIButton) {
completion?(self.getFavoritePet())
self.dismiss(animated: true)
}
第二部分是你要写接收数据的代码
// ProfileVC
// MARK: - Button Select Your Fav Pet Event
@IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
vc.completion = { petName in
self.setPetName(pet: petName)
}
self.present(vc, animated: true)
}
// MARK: - API call "LogIn"
func apiCallLogIn() {
if Utils.shareInstance.isInternetAvailable() {
Utils.shareInstance.showLoader(vc: self)
let param: Parameters = ["username": txtEmail.text ?? "", "password": txtPassword.text ?? ""]
let url = AppConstant.API_URL.apiLogIn
AF.request(url, method: .post, parameters: param).responseDecodable(of: UserModel.self) { response in
switch response.result {
case .success(let user):
Utils.shareInstance.hideLoader()
if response.value != nil {
print("user API Call --> \(user)")
if user.result == true {
print("true --> \(String(describing: user.message))")
self.userModel = user
AppConstant.userDefaults.setLoggedIn(value: true)
AppConstant.userDefaults.setUserData(data: user)
let homeVC = self.storyboard?.instantiateViewController(withIdentifier: AppConstant.ViewController.homeVC) as! HomeViewController
self.navigationController?.pushViewController(homeVC, animated: true)
} else {
print("false --> \(String(describing: user.message))")
Utils.shareInstance.displayMyAlertMessage(title: "Error", message: user.message ?? "", vc: self)
}
} else {
Utils.shareInstance.displayMyAlertMessage(title: "Error", message: "No Data Found!", vc: self)
}
case .failure(let error):
print("case 2: failure")
Utils.shareInstance.hideLoader()
Utils.shareInstance.displayMyAlertMessage(title: "Error", message: error.localizedDescription, vc: self)
}
}
// this is also working
// AF.request(url, method: .post, parameters: param).responseJSON { response in
//
// switch response.result {
//
// case .success(let JSON):
// Utils.shareInstance.hideLoader()
//
// let response = JSON as? [String:Any] ?? [:]
//
// print("response --> \(response)")
//
// case .failure(let error):
// Utils.shareInstance.displayMyAlertMessage(title: "Error", message: error.localizedDescription, vc: self)
// }
//
// }
} else {
Utils.shareInstance.displayMyAlertMessage(title: "No Internet", message: "Connection Failed! Check Your Internet Connection!", vc: self)
}
}
// MARK: - Objc Method for Search
@objc func searchTextField(_ sender: UITextField) {
self.arrSearchItems.removeAll()
if txtEnterSearchText.text?.trimmingCharacters(in: .whitespaces).count != 0 {
isSearching = true
for item in arrItems {
if let search = txtEnterSearchText.text {
let range1 = item.title?.lowercased().range(of: search, options: .caseInsensitive, range: nil, locale: nil)
let range2 = item.category?.lowercased().range(of: search, options: .caseInsensitive, range: nil, locale: nil)
let range3 = item.price?.lowercased().range(of: search, options: .caseInsensitive, range: nil, locale: nil)
if range1 != nil || range2 != nil || range3 != nil {
self.arrSearchItems.append(item)
}
}
}
print("search array --> \(arrSearchItems.count)")
} else {
isSearching = false
print("Without Search")
}
self.tableVwHome.reloadData()
}
// MARK: - API Call "Category"
func apiCallCategory() {
if Utils.shareInstance.isInternetAvailable() {
Utils.shareInstance.showLoader(vc: self)
let url = AppConstant.API_URL.apiCategory
AF.request(url, method: .post).responseDecodable(of: CategoriesModel.self) { response in
switch response.result {
case .success(let categoryModel):
Utils.shareInstance.hideLoader()
if response.value != nil {
print("categoryModel API Call --> \(categoryModel)")
self.arrCategories = categoryModel.categories ?? [Category]()
// guard let category = categoryModel.categories else { return }
// self.arrCategories.append(contentsOf: category) // this will append data every time view gets reload // query
print("arrCategories --> \(self.arrCategories)")
DispatchQueue.main.async {
self.tableVwHome.reloadData()
}
} else {
Utils.shareInstance.displayMyAlertMessage(title: "Error", message: "No Data Found!", vc: self)
}
case .failure(let error):
print("case 2: failure")
Utils.shareInstance.hideLoader()
Utils.shareInstance.displayMyAlertMessage(title: "Error", message: error.localizedDescription, vc: self)
}
}
} else {
Utils.shareInstance.displayMyAlertMessage(title: "No Internet", message: "Connection Failed! Check Your Internet Connection!", vc: self)
}
}
// MARK: - Segment Control Event
@IBAction func segmentControl_Event(_ sender: Any) {
if segmentControl.selectedSegmentIndex == 0 {
topConstraintxtSearch.constant = 0
topConstraintShowOnly.constant = 0
heightConstrainttxtSearch.constant = 0
heightConstraintShowOnly.constant = 0
vWShowOnly.layoutIfNeeded()
txtEnterSearchText.layoutIfNeeded()
vWShowOnly.isHidden = true
txtEnterSearchText.isHidden = true
apiCallCategory()
} else {
topConstraintxtSearch.constant = 20
topConstraintShowOnly.constant = 20
heightConstrainttxtSearch.constant = 50
heightConstraintShowOnly.constant = 35
vWShowOnly.layoutIfNeeded()
txtEnterSearchText.layoutIfNeeded()
vWShowOnly.isHidden = false
txtEnterSearchText.isHidden = false
if isShowBtnSelected {
btnShowStockItems.setImage(UIImage(named: "dotedCircle"), for: .normal)
let filteredArray = arrItems.filter({ $0.inStock == true })
print("In Stock Items --> \(filteredArray.count)")
self.arrItems = filteredArray
self.tableVwHome.reloadData()
isShowBtnSelected = true
} else {
btnShowStockItems.setImage(UIImage(named: "circle"), for: .normal)
getItemsData()
print("mainArray count --> \(arrItems.count)")
isShowBtnSelected = false
}
}
}
// MARK: - Button Show Only Stock Items Event
@IBAction func btnShowStockItems_Event(_ sender: UIButton) {
if isShowBtnSelected {
btnShowStockItems.setImage(UIImage(named: "circle"), for: .normal)
getItemsData()
print("mainArray count --> \(arrItems.count)")
isShowBtnSelected = false
} else {
btnShowStockItems.setImage(UIImage(named: "dotedCircle"), for: .normal)
let filteredArray = arrItems.filter({ $0.inStock == true })
print("In Stock Items --> \(filteredArray.count)")
self.arrItems = filteredArray
self.tableVwHome.reloadData()
isShowBtnSelected = true
}
}
// MARK: - TextField Delegate
extension HomeViewController: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
txtEnterSearchText.resignFirstResponder()
return true
}
}
// MARK: - Save Items
func saveItems() {
item = ItemsModel(imgItem: selectedImgString, title: txtEnterTitle.text, category: dropDown.text, price: txtEnterPrice.text, inStock: isShowBtnSelected ? true : false)
let arrayItems = AppConstant.userDefaults.retrieveItemsData()
self.arrItems.append(contentsOf: arrayItems)
self.arrItems.append(item)
print("Array Items --> \(arrItems)")
Toast.show(message: "Item saved successfully", controller: self)
AppConstant.userDefaults.setItemsData(data: self.arrItems)
}
// MARK: - Button Save Event
@IBAction func btnSave_Event(_ sender: UIButton) {
if checkTextFieldsEmpty() == false {
print("All TextFields are filled")
saveItems()
self.navigationController?.popViewController(animated: true)
selectedImgString = nil
txtEnterTitle.text = ""
txtEnterPrice.text = ""
dropDown.text = ""
btnInStock.setImage(UIImage(named: "circle"), for: .normal)
} else {
print("TextFields are empty")
}
}
// MARK: - ImagePickerDelegate
extension AddItemViewController: ImagePickerDelegate {
func didSelect(image: UIImage?) {
let selectedImg = image?.resizeImageWithCGSize(newSize: CGSize(width: 80, height: 80))
self.selectedImgString = selectedImg?.jpegData(compressionQuality: 1)?.base64EncodedString()
// print("selectedImgString --> \(selectedImgString)")
}
}
import Foundation
import UIKit
import Reachability
class Utils: NSObject {
static var shareInstance = Utils()
var activityIndicator = UIActivityIndicatorView(style: .large)
// MARK: - Display Alert for Empty TextFields
func displayMyAlertMessage(title: String, message: String, vc: UIViewController) {
let myAlert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
myAlert.addAction(okAction)
vc.present(myAlert, animated: true, completion: nil)
}
// MARK: - Show Loader
func showLoader(vc: UIViewController) {
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
vc.view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true
activityIndicator.startAnimating()
}
// MARK: - Hide Loader
func hideLoader() {
activityIndicator.stopAnimating()
}
// MARK: - Check Internet Availability
func isInternetAvailable() -> Bool {
let reachability = try! Reachability()
if reachability.connection == .wifi || reachability.connection == .cellular {
print("Internet is available")
return true
} else {
print("Connection Failed! Check Your Internet Connection!")
return false
}
}
}
// MARK: - Configure Cell
func ConfigureCell(object: ItemsModel) {
self.selectedBackgroundView = UIView()
self.selectedBackgroundView?.backgroundColor = .systemBackground
self.lblPrice.text = "\("$") \(object.price ?? "")"
let imgStr = object.imgItem
if let decodedData = Data(base64Encoded: imgStr ?? "", options: .ignoreUnknownCharacters) {
self.imgItem.image = UIImage(data: decodedData)
}
self.lblTitle.text = object.title
self.lblCategory.text = object.category
let inStock = object.inStock
self.lblInStock.text = inStock ?? false ? "(In stock)" : "(Out of stock)"
}