从自定义表格视图单元格获取数据到另一个 VC?

Posted

技术标签:

【中文标题】从自定义表格视图单元格获取数据到另一个 VC?【英文标题】:Getting data from custom tableview cell to another VC? 【发布时间】:2017-12-15 12:00:45 【问题描述】:

寻求一些帮助或朝着正确的方向轻推,因为我似乎无法弄清楚这一点。我正在尝试将自定义表格视图单元格上的电子邮件标签中的文本获取到另一个 VC 中,在那里我将有一个联系表。我在 tableview 单元格上有一个按钮,所以理想情况下,这将进入一个新的 VC,在那里我可以访问电子邮件字段,但对于那个特定的单元格。我已经研究过使用 preparetoseugue 函数来实现 indexpath.row 索引,但到目前为止还没有运气。

这是我的自定义表格视图单元格:

//
//  RentalCell.swift
//  Login
//
//  Created by George Woolley on 02/12/2017.
//  Copyright © 2017 George Woolley. All rights reserved.
//

import UIKit
import Foundation
import Firebase
import MessageUI

class RentalCell: UITableViewCell, MFMailComposeViewControllerDelegate 
    var rental: Rental!

    @IBOutlet weak var rentalTitleLbl: UILabel!
    @IBOutlet weak var rentalPriceLbl: UILabel!
    @IBOutlet weak var rentalTypeLbl: UILabel!
    @IBOutlet weak var bondLbl: UILabel!
    @IBOutlet weak var rentLbl: UILabel!
    @IBOutlet weak var dateAvalLbl: UILabel!
    @IBOutlet weak var petsLbl: UILabel!
    @IBOutlet weak var descriptionLbl: UILabel!
    @IBOutlet weak var emailField: UILabel!
    @IBOutlet weak var rentalImage: UIImageView!

    func configureCell(rental: Rental, image: UIImage?) 
        self.rental = rental

        self.rentalTitleLbl.text = rental.title
        self.rentalPriceLbl.text = rental.price
        self.rentalTypeLbl.text = rental.rentalType
        self.bondLbl.text = rental.bond
        self.rentLbl.text = rental.price
        self.dateAvalLbl.text = rental.dateAval
        self.petsLbl.text = rental.pets
        self.descriptionLbl.text = rental.description
        self.emailField.text = rental.email

        if image != nil 
            //Image already in cache
            self.rentalImage.image = image
         else 
            // download image from Firebase
            let ref = Storage.storage().reference(forURL: rental.imageURL!)
            ref.getData(maxSize:  2 * 1024 * 1024, completion:  (data, error) in
                if error != nil 
                    print("An error has occured downloading image")
                 else 
                    print("Image downloaded")
                    if let imageData = data 
                        if let img = UIImage(data: imageData) 
                            self.rentalImage.image = img
                            RentalTableViewVC.imageCache.setObject(img, forKey: rental.imageURL! as NSString)
                        
                    
                
            )
        
    

这是我的 tableViewVC:

//
//  MainVC.swift
//  Login
//

import UIKit
import Firebase
import FirebaseDatabase

class AvertisingVC: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate 
    @IBOutlet weak var titleField: UITextField!
    @IBOutlet weak var dateAvalField: UITextField!
    @IBOutlet weak var rentalTypeField: UITextField!
    @IBOutlet weak var petsField: UITextField!
    @IBOutlet weak var furnishedField: UITextField!
    @IBOutlet weak var bondField: UITextField!
    @IBOutlet weak var rentField: UITextField!
    @IBOutlet weak var descriptionField: UITextView!
    @IBOutlet weak var addImage: UIImageView!
    @IBOutlet weak var emailField: UITextField!

    var imageSelected = false
    let datePicker = UIDatePicker()
    var imagePicker: UIImagePickerController!
    var databaseRef:DatabaseReference?   //reference to firebase dba
    let rentalTypes = ["Room in shared house", "Entire House","Room Share", "Apartment", "Cottage", "Other"]
    let petsAllowed = ["Yes", "No"]
    let rentalTypePicker = UIPickerView()
    let petsAllowedPicker = UIPickerView()

    func numberOfComponents(in pickerView: UIPickerView) -> Int 
        return 1
    

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int 
        return rentalTypes.count
    

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? 
        return rentalTypes[row]
    

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) 
        rentalTypeField.text = rentalTypes[row]
        rentalTypeField.resignFirstResponder()
    

    func createDatePicker() 
        //toolbar
        let toolbar = UIToolbar()
        toolbar.sizeToFit()
        //done button
        let done = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(datePickerDonePressed))
        toolbar.setItems([done], animated: false)
        //add picker to text field
        dateAvalField.inputAccessoryView = toolbar
        dateAvalField.inputView = datePicker
        //format picker for date
        datePicker.datePickerMode = .date
    

    @objc func datePickerDonePressed() 
        //formate date
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        dateFormatter.timeStyle = .none
        let dateString = dateFormatter.string(from: datePicker.date)
        dateAvalField.text = "\(dateString)"
        self.view.endEditing(true)
    

    func setupRentalTypePicker() 
        rentalTypeField.inputView = rentalTypePicker
        rentalTypePicker.dataSource = self
        rentalTypePicker.delegate = self

        rentalTypeField.textAlignment = .center
        rentalTypeField.placeholder = "Select rental type"
    

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
        if let image = info[UIImagePickerControllerEditedImage] as? UIImage 
            addImage.image = image
            imageSelected = true
         else 
            print("Invalid image from picker")
        
        imagePicker.dismiss(animated: true, completion: nil)
    

    override func viewDidLoad() 
        super.viewDidLoad()

        imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = true
        imagePicker.delegate = self

        //Firebase Ref
        databaseRef = Database.database().reference().child("Rentals") //can add .child(string:root) to add root dir to dba
        //Date Picker
        createDatePicker()
        //rentalTypePicker
        setupRentalTypePicker()
    

    @IBAction func backBtnPressed(_ sender: Any) 
        self.dismiss(animated: true, completion: nil)
    

    @IBAction func submitForm(_ sender: Any)       // Send data to firebase on submit

        guard let img = addImage.image, imageSelected == true else 

            let alert = UIAlertController(title: "You must upload one image to proceed", message: "It's recommended you upload one image before continuing.", preferredStyle: .alert)

            alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))

            self.present(alert, animated: true)

            return
        

        //Upload image with unique ID as a key
        if let imageData = UIImageJPEGRepresentation(img, 0.2) 

            let imageUID = UUID().uuidString
            let metaData = StorageMetadata()
            metaData.contentType = "image/jpeg"

            DataService.ds.StorageREF.child(imageUID).putData(imageData, metadata: metaData)  (metadata, error) in
                if error != nil 
                    print("Error occured uploading data to firebase")
                 else 
                    print("Successfully uploaded image")

                    let downloadURL = metadata?.downloadURL()?.absoluteString

                    if let url = downloadURL 
                        self.postDataToFirbase(imgURL: url)
                    
                
            
        

        let alertController = UIAlertController(title: "Success!", message: "You have successfully listed a rental", preferredStyle: .alert)
        let defaultAction = UIAlertAction(title: "Close Alert", style: .default, handler: nil)
        alertController.addAction(defaultAction)

        present(alertController, animated: true, completion: nil)
    

    func postDataToFirbase(imgURL: String) 
        let data: Dictionary<String, AnyObject> = [
       "title": titleField.text as AnyObject,
        "price": rentField.text as AnyObject,
        "description": descriptionField.text as AnyObject,
        "bond": bondField.text as AnyObject,
        "date": dateAvalField.text as AnyObject,
        "type": rentalTypeField.text as AnyObject,
        "pets": petsField.text as AnyObject,
        "imageURL": imgURL as AnyObject,
        "email": emailField.text as AnyObject
        ]

        //Post data
        let postDataTo = DataService.ds.DBrefRentals.childByAutoId()
        postDataTo.setValue(data)
        //Clear screen
        titleField.text = ""
        rentField.text = ""
        descriptionField.text = ""
        bondField.text = ""
        rentalTypeField.text = ""
        dateAvalField.text = ""
        petsField.text = ""
        furnishedField.text = ""
        emailField.text = ""
        addImage.image = #imageLiteral(resourceName: "house")
    

    @IBAction func addImagePressed(_ sender: Any) 
        present(imagePicker, animated: true, completion: nil)
    

【问题讨论】:

Passing Data between View Controllers的可能重复 只是关于你的主题行的注释......你永远不应该考虑从应用程序的视觉元素中获取数据,除非它是响应用户编辑的简单数据模型更新。如果您正在寻找要传递的信息源,请从与您的单元格匹配的 Rental 对象中获取它。 谢谢菲利普。这真的是我一直在寻找的。我知道我正在尝试做的更多的是一种变通方法/hacky 方法,已经研究出如何通过 indexpath 的值从 Rental Object 获取值。 【参考方案1】:

在“Sender”类中声明一个变量 例子: var valueName: String? 接下来的事情是为 segue 做准备 示例:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.destination is ValuesTableViewController
    
        let vc = segue.destination as? ValuesTableViewController
        vc?.valueName = "Some string u want to send"
    

其中 ValuesTableViewController 是 Receivers View Controller 类

最后要做的是在代码中调用 segue 方法,您希望将用户重定向到下一个屏幕。

示例:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    let cell = tableView.cellForRow(at: indexPath) as! UnitTableViewCell
    if let valueName = cell.valueLabel.text 
        print(valueName)
        sendingName = valueName
        if let color = cell.leftColorView.backgroundColor 
            sendingColor = color
        
        self.performSegue(withIdentifier: "goToValues", sender: self)
        

如果用户单击 TableView 中的一个单元格,您会将他重定向到下一个屏幕,这只是一个示例,您也可以在其他情况下使用它。

最后一步:在receiver ViewController 中创建一个变量

var valueName: String?

然后你可以在任何你喜欢的地方使用它

快乐编码

【讨论】:

以上是关于从自定义表格视图单元格获取数据到另一个 VC?的主要内容,如果未能解决你的问题,请参考以下文章

将数据从自定义表格视图单元格传递到 UIView 控制器

如何从自定义表格视图单元类中获取对表格视图控制器的引用

从自定义单元格重新加载表格视图数据

从自定义单元格 iPhone 中的 textField 获取值

将数组从自定义单元格发送到另一个视图控制器

无法从自定义表格视图单元格按钮中删除行