使用单独的控制器将自定义单元格中的标签设置为数组中的名称

Posted

技术标签:

【中文标题】使用单独的控制器将自定义单元格中的标签设置为数组中的名称【英文标题】:Set labels in a custom cell to names from an array using a separate controller 【发布时间】:2020-07-31 15:58:57 【问题描述】:

我有一个带表格的视图控制器。视图控制器有一个按钮,可以连接到另一个具有 4 个文本字段的控制器。有一个名称文本字段和其他三个可以输入数字的字段。当用户按下 add 时,会附加一个数组,并在更新前一个视图控制器中的表时关闭视图控制器。然后向用户呈现一个添加了新单元格的表格。该单元格有 4 个标签。

我试图弄清楚如何将单元格中的每个标签设置为创建新单元格的视图控制器中的 4 个文本字段。这是创建单元格的视图控制器的图片:

这是按下加号按钮时的视图控制器,它通过更新数组来创建单元格:

我希望能够设置最左边的标签来表示每次添加到数组中的名称。当一个人第一次单击加号按钮时,文本字段视图控制器将弹出,用户可以将名称放在文本字段中。当按下添加按钮时,左侧的标签将显示附加数组的控制器中的名称。通过视图控制器添加的下一个名称将位于先前输入的名称下方的单元格中,依此类推。我需要让数组正确显示文本。我最初希望单元格具有用户可以将信息放入其中的文本字段,但单元格数据没有正确发送到 firebase 数据库。

这是第一个视图控制器的代码:

import UIKit
import Firebase

class ConsiderationsTestViewController: UIViewController, UITextFieldDelegate 

@IBOutlet weak var tableView: UITableView!

static var numberOfPeople: [String] = []

var AddPersonCell = "AddPersonCell"

@IBOutlet weak var CompanyImage: UIImageView!

@IBOutlet weak var companyNameTextFieldConsiderations: UITextField!

@IBOutlet weak var companyDescriptionTextFieldConsiderations: UITextField!

@IBOutlet weak var startDateTextFieldConsiderations: UITextField!

@IBOutlet weak var endDateTextFieldConsiderations: UITextField!

let datePickerS = UIDatePicker()
let datePickerE = UIDatePicker()

    var database: Database!
    var storage: Storage!
    var selectedImage: UIImage?
    
    var ref:DatabaseReference?
    var databaseHandle:DatabaseHandle = 0
    
    let dbref = Database.database().reference()
    let uid = Auth.auth().currentUser?.uid
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
        
        self.companyNameTextFieldConsiderations.delegate = self
        self.companyDescriptionTextFieldConsiderations.delegate = self
        
        // Set the Firebase reference
        ref = Database.database().reference()
        
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ConsiderationsTestViewController.handleSelectCompanyImageView))
         CompanyImage.addGestureRecognizer(tapGesture)
         CompanyImage.isUserInteractionEnabled = true

        self.navigationController!.navigationBar.isTranslucent = false
        
        navigationItem.backBarButtonItem = UIBarButtonItem(
        title: "", style: .plain, target: nil, action: nil)
        
        createDatePickerForStart()
        
        createDatePickerForEnd()
        
        NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
    

  @objc func loadList()
    //load data here
    self.tableView.reloadData()


    @objc func handleSelectCompanyImageView() 

        let pickerController = UIImagePickerController()
        pickerController.delegate = self
        pickerController.allowsEditing = true
        present(pickerController, animated: true, completion: nil)
                    
    
    @IBAction func AddPersonTapped(_ sender: Any) 
  
       

    @IBAction func sendButtonTapped(_ sender: Any) 
    
    let companyNameC = companyNameTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
    let companyDescriptionC = companyDescriptionTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
    
    let today = Date()
    let formatter1 = DateFormatter()
    formatter1.dateFormat = "MMM d y"
    print(formatter1.string(from: today))
    let todaysDate = formatter1.string(from: today)
            
    let storageRef = Storage.storage().reference(forURL: "STORAGE URL HERE")
    let imageName = companyNameTextFieldConsiderations.text!
    let storageCompanyRef = storageRef.child("Company_Image_Considerations").child("\(todaysDate)").child(imageName)
    let companyDescriptionTextFieldText = companyDescriptionTextFieldConsiderations.text
    let dateToStart = startDateTextFieldConsiderations.text
    let dateToDecide = endDateTextFieldConsiderations.text
    let companyRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName)

    let considerationInfluencerRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName).child("Users")
    
     //let values = ["Feed_Quantity": "feedTFC", "Story_Quantity": "storyTFC", "Compensation": "compensationTFC"]
    
        guard let imageSelected = self.CompanyImage.image else 
            print ("Avatar is nil")
            return
                
                   
                var dict: Dictionary<String, Any> = [
                    "Company Image": "",
                    "Company Description": companyDescriptionTextFieldText!,
                    "Start Date": dateToStart!,
                    "Decision Date": dateToDecide! ]
    
                   
        guard let imageData = imageSelected.jpegData(compressionQuality: 0.5) else 
            return
                
    
                let metadata = StorageMetadata()
                metadata.contentType = "image/jpeg"
                storageCompanyRef.putData(imageData, metadata: metadata, completion:
                 (StorageMetadata, error) in
                if (error != nil) 
                return
                    
                            
                storageCompanyRef.downloadURL  (url, error) in
                if let metadateImage = url?.absoluteString 
                dict["Company Image"] = metadateImage
                   
                companyRef.updateChildValues(dict, withCompletionBlock:  
                (error, ref) in
                if error == nil 
                print("Done")
                return
                    
                  
                )
               
             
                            
                                   storageRef.updateMetadata(metadata)  metadata, error in
                                    if error != nil 
                                    //Uh-oh, an error occurred!
                                     else 
                                    // Updated metadata for 'images/forest.jpg' is returned
                                
                            
                        )
    
      //        considerationInfluencerRef.updateChildValues(values as [AnyHashable : Any])  (error, ref) in
      //        if error != nil 
      //        print(error ?? "")
      //        return
      //                           
    
      self.navigationController?.popViewController(animated: true)
      //           
       


    func createDatePickerForStart() 
    // center text in field
    startDateTextFieldConsiderations.textAlignment = .center
    
    // toolbar
    let toolbar = UIToolbar()
    toolbar.sizeToFit()
    
    // barbutton
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedStart))
    toolbar.setItems([doneButton], animated: true)
    
    // assign toolbar to textfield
    
    startDateTextFieldConsiderations.inputAccessoryView = toolbar
    
    // assign datePicker to text field
    startDateTextFieldConsiderations.inputView = datePickerS
    
    // date picker mode
    datePickerS.datePickerMode = .date
    
     
 
    func createDatePickerForEnd() 
    // center text in field
    endDateTextFieldConsiderations.textAlignment = .center
    
    // toolbar
    let toolbar = UIToolbar()
    toolbar.sizeToFit()
    
    // barbutton
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedEnd))
    toolbar.setItems([doneButton], animated: true)
    
    // assign toolbar to textfield
    endDateTextFieldConsiderations.inputAccessoryView = toolbar
    
    // assign datePicker to text field
    endDateTextFieldConsiderations.inputView = datePickerE
    
    // date picker mode
    datePickerE.datePickerMode = .dateAndTime
       

    @objc func donePressedStart() 
    // formatter
    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    formatter.timeStyle = .none
    
    startDateTextFieldConsiderations.text = formatter.string(from: datePickerS.date)
    self.view.endEditing(true)
     

    @objc func donePressedEnd() 
    // formatter
    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    formatter.timeStyle = .medium
    
    endDateTextFieldConsiderations.text = formatter.string(from: datePickerE.date)
    self.view.endEditing(true)
            

    @IBAction func testTapped(_ sender: Any) 
    print(ConsiderationsTestViewController.numberOfPeople)
           
        
    
    extension ConsiderationsTestViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate 
               func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) 
                   //print("did Finish Picking Media")
                   if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerEditedImage")] as? UIImage
                       selectedImage = image
                       CompanyImage.image = image
                   
                   dismiss(animated: true, completion: nil)
               
           

      extension ConsiderationsTestViewController: UITableViewDelegate, UITableViewDataSource 
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return ConsiderationsTestViewController.numberOfPeople.count
         

    func numberOfSections(in tableView: UITableView) -> Int 
    return 1
         


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = tableView.dequeueReusableCell(withIdentifier: AddPersonCell, for: indexPath) as! ConsiderationsCell
    
    return cell
       

     

这是第二个视图控制器的代码:

import UIKit
import Firebase

class DropDownCellViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UITextFieldDelegate 

var numberOfPeople = [String]()

var users = [User]()

var userName = [String]()

var filteredNames: [String]!

let dropDownCell = "dropDownCell"

var emptyField = [String]()

override func viewDidLoad() 
super.viewDidLoad()

updateDataArray()

tableView.register(UserCell.self, forCellReuseIdentifier: dropDownCell)

filteredNames = userName

    tableView.delegate = self
    tableView.dataSource = self
    nameTextField.delegate = self
       
    tableView.isHidden = true
       
       // Manage tableView visibility via TouchDown in textField
nameTextField.addTarget(self, action: #selector(textFieldActive), for: UIControl.Event.touchDown)
   

@IBOutlet weak var nameTextField: NoCopyPasteUITextField!

@IBOutlet weak var tableView: UITableView!

@IBOutlet weak var gridTextField: UITextField!

@IBOutlet weak var storyTextField: UITextField!

@IBOutlet weak var compensationTextField: UITextField!

@IBAction func textFieldChanged(_ sender: AnyObject) 
    tableView.isHidden = true


@IBAction func cancelButtonTapped(_ sender: Any) 
    self.navigationController?.popViewController(animated: true)


@IBAction func addButtonTapped(_ sender: Any) 
    
    ConsiderationsTestViewController.numberOfPeople.append("\(nameTextField.text!)")
    
    self.navigationController?.popViewController(animated: true)
    
    print(ConsiderationsTestViewController.numberOfPeople)
    
    DispatchQueue.main.async 
       NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
            
    

  let searchController = UISearchController(searchResultsController: nil)

  override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
    
      guard let touch:UITouch = touches.first else
      
          return;
      
      if touch.view != tableView
      
          nameTextField.endEditing(true)
          tableView.isHidden = true
      
    

   @objc func textFieldActive() 
       tableView.isHidden = !tableView.isHidden
   

  // MARK: UITextFieldDelegate
   func textFieldDidEndEditing(_ textField: UITextField) 
       // TODO: Your app can do something when textField finishes editing
       print("The textField ended editing. Do something based on app requirements.")
   
   
   func textFieldShouldReturn(_ textField: UITextField) -> Bool 
       textField.resignFirstResponder()
       return true
   


  func numberOfSections(in tableView: UITableView) -> Int 
      // #warning Incomplete implementation, return the number of sections
    return 1
   

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    // #warning Incomplete implementation, return the number of rows
    
    return filteredNames.count
    

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    
    let cell = tableView.dequeueReusableCell(withIdentifier: dropDownCell, for: indexPath) as!
    UserCell
    
    let user = users[indexPath.row]
    cell.textLabel?.text = user.name
    
    if let profileImageUrl = user.profileImageUrl 
    
    cell.profileImageView.loadImageUsingCacheWithUrlString(urlString: profileImageUrl)
        
    
    return cell


func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
return 72


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    // Row selected, so set textField to relevant value, hide tableView
           // endEditing can trigger some other action according to requirements
           nameTextField.text = userName[indexPath.row]
           tableView.isHidden = true
           nameTextField.endEditing(true)
       

//Mark: Search Bar Config
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
    
    filteredNames = []
    
    if searchText == "" 
        filteredNames = userName
        
    
    else 
        for names in userName 
            
            if names.lowercased().contains(searchText.lowercased()) 
                
                filteredNames.append(names)
            
        
    
    self.tableView.reloadData()


func updateDataArray() 
    
    Database.database().reference().child("users").observe(.childAdded, with:  (snapshot) in
        
        if let dictionary = snapshot.value as? [String: AnyObject] 
            
            let user = User()
            //self.setValuesForKeys(dictionary)
            user.name = dictionary["name"] as? String
            user.email = dictionary["email"] as? String
            user.facebookUrl = dictionary["facebookUrl"] as? String
            user.instagramUrl = dictionary["instagramUrl"] as? String
            user.linkedInUrl = dictionary["linkedInUrl"] as? String
            user.profileImageUrl = dictionary["profileImageUrl"] as? String
            user.twitterUrl = dictionary["twitterUrl"] as? String
            user.id = dictionary["id"] as? String
            user.userType = dictionary["userType"] as? String
            
            self.users.append(user)
            self.userName.append(user.name!)
            self.filteredNames.append(user.name!)
            
            DispatchQueue.main.async 
            self.tableView.reloadData()
            
        
        
    , withCancel: nil)
    
    
  
 

我正在尝试使用在名为 renameLabel 的 addButton 函数中调用的函数附加标签。这里是func重命名标签代码:

func renameLabel() 
let cell = ConsiderationsTestViewController.init().tableView.dequeueReusableCell(withIdentifier: AddPersonCell) as! ConsiderationsCell
    
cell.nameLabelC.text = ("\(ConsiderationsTestViewController.numberOfPeople)")

我现在收到错误:

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

任何帮助都会很棒!

【问题讨论】:

【参考方案1】:

首先在第二个VC之上创建一个协议。

protocol UpdatingArrayDelegate: class 
    func updateArray(newArray: [String])

在第二个 VC 里面创建:

var updatingArrayDelegate: UpdatingArrayDelegate!

然后在推送到第二个 VC 之前,将委托设置为 self:

@objc func pushToSecondVCButtonTapped() 
    let destVC = secondVC()
    updatingArrayDelegate = self
    self.navigationController?.pushViewController(destVC, animated: true)
    // if you don't have self.navigationController use:
    // present(destVC(), animated: true, completion: nil)

现在在按 addButton 完成 secondVC 上的编辑时,请执行以下操作:

@objc func doneButtonTapped() 
    updatingArrayDelegate?.updateArray(newArray: myNewArrayCreatedOnThisSecondVC)
    self.navigationController?.popViewController(animated: true)

然后先添加委托函数

extension FirstVC: UpdatingArrayDelegate 
    func updateArray(newArray: [String]) 
        print("updateArray")
        let myCell = myTableView.cellForRow(at: IndexPath(row: x, section: y)) as! MyCell
        myCell.textLabel1.text = newArray[0]
        myCell.textLabel2.text = newArray[1]
        myCell.textLabel3.text = newArray[2]
        myCell.textLabel4.text = newArray[3]
    

您可以这样考虑委托: 老板(secondVC)给工人(firstVC)一个做什么的协议。 Worker 读取协议并使用协议中给出的功能进行工作。在工人跑向老板之前,他必须确保他可以完成下一个任务(写在他将要拥有的协议上。)

【讨论】:

以上是关于使用单独的控制器将自定义单元格中的标签设置为数组中的名称的主要内容,如果未能解决你的问题,请参考以下文章

填充 UITableViewController 时,自定义单元格中的标签为空

Swift:自定义单元格中的 IBoutlets 为零

将自定义单元格从一个视图控制器传递到另一个视图控制器

文本字段标签和表格视图

如何将自定义样式添加到 Angular Material Table 单元格的一小部分?

如何使用自定义表格视图单元格中识别的点击手势从 UILabel 呈现视图控制器?