Помещение различных пользовательских типов ячеек в табличное представление - PullRequest
0 голосов
/ 20 мая 2018

У меня возникли проблемы при попытке заполнить одно табличное представление различными пользовательскими типами ячеек.Я попытался удалить все нерелевантные части кода.У меня может быть много последующих вопросов, но в операторе dequereusablecell (в функции cellforrow) я не могу уменьшить ячейку до типов FilterTableViewCell или FilterTableViewCell2, хранящихся в массиве cellTypes.Я получаю сообщение об ошибке «Типы массива теперь пишутся в скобках вокруг типа элемента» ... он думает, что я пытаюсь уменьшить значение до типа массива в противоположность типу ячейки в данном индексе массива cellTypes.Надеюсь, это понятно.

Я также пытался поместить один оператор dequereusablecell в каждом случае оператора switch, но я получаю ошибки в других частях моего кода.Он в основном обрабатывает FIlterTableViewCell и FilterTableViewCell2, как если бы они были типом базового класса (UITableViewCell), и поэтому не может получить доступ к свойствам в этих двух подклассах.Надеюсь, это понятно.но если вы заметили что-либо вообще проблемное в других частях моего кода (особенно о том, как я использую массивы), дайте мне знать.

Код:

import Foundation
import UIKit

class FilterViewController: UIViewController, UITableViewDelegate,UITableViewDataSource, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate,UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
    let properties = ["Diet","Body Type","Looking For","Ethnicity"]
    var values:NSArray!
    let dietOpts:NSArray = ["Vegan","Plant-based","Vegetarian","Meat Eater"]
    let bodytypeOpts:NSArray = ["Muscular","Athletic","Lean","Husky","Chubby","Large","Fat"]
    let lookingforOpts:NSArray = ["Friends","Dates","Chat","Networking","Relationship","Right Now"]
    let ethnicityOpts:NSArray = ["Hispanic/Latino","Black","White","Middle Eastern","South Asian","Asian","Native American","Pacific Islander"]

    var userFilterTable : UITableView!

    var cellTypes = [FilterTableViewCell.self,FilterTableViewCell.self,FilterTableViewCell2.self,FilterTableViewCell2.self]
    var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),FilterTableViewCell2(),FilterTableViewCell2()]
    let cellIDs = ["cellId","cellId","cellId2","cellId2"]
    var toolBar : UIToolbar!
    var i:Int!
    var myUIPicker = UIPickerView()
    var multiplePicker = MultiplePicker()
    var myValues: NSArray!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.blue

        let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
        let displayWidth: CGFloat = self.view.frame.width
        let displayHeight: CGFloat = self.view.frame.height
        userFilterTable = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))

        userFilterTable.register(FilterTableViewCell.self, forCellReuseIdentifier: "cellId")
        userFilterTable.register(FilterTableViewCell2.self, forCellReuseIdentifier: "cellId2")

        userFilterTable.backgroundColor = UIColor.clear
        userFilterTable.isScrollEnabled = false
        userFilterTable.delegate = self
        userFilterTable.dataSource = self
        userFilterTable.rowHeight = 40

        self.userFilterTable.reloadData()
        self.view.addSubview(userFilterTable)
    }

    @objc func buttonAction(_ sender: UIButton!){
        print("Button tapped")
    }

    func generalPicker(){
        myUIPicker.becomeFirstResponder()
        self.myUIPicker.delegate = self
        self.myUIPicker.dataSource = self
    }

    @objc func donePicker() {
        reminderCells[i].valueTextField.resignFirstResponder()
    }

    func doMultiplePicker(){
        multiplePicker.becomeFirstResponder()
        //multiplePicker.delegate = self
        //multiplePicker.dataSource = self

        reminderCells[i].valueTextField.backgroundColor = UIColor.white
        toolBar = UIToolbar()
        toolBar.sizeToFit()
    }

    @objc func donePicker2() {
        reminderCells[i].valueTextField.text = multiplePicker.str
        reminderCells[i].valueTextField.resignFirstResponder()
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        reminderCells[indexPath.row].valueTextField.becomeFirstResponder()

        i = indexPath.row
        print(properties[indexPath.item]) //print("Diet")
        switch properties[indexPath.item] {
        case "Diet":
            myValues = dietOpts
            generalPicker()
        case "BodyType":
            myValues = bodytypeOpts
            generalPicker()
        case "Looking For":
            myValues = lookingforOpts
            generalPicker()
        case "Ethnicity":
            myValues = bodytypeOpts
            doMultiplePicker()
        default:
            print("Some other character")
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // retuen no of rows in sections
        return properties.count
    }

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

        print(indexPath.row)
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! cellTypes[indexPath.row]

        switch properties[indexPath.item]{
            case "Diet","Body Type":
                let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
                toolBar.setItems([doneButton], animated: false)
                cell.valueTextField.inputAccessoryView = toolBar
                cell.valueTextField.inputView = myUIPicker
            case "Looking For","Ethnicity":
                multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
                multiplePicker.myValues = ethnicityOpts as! [String]
                let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
                toolBar.setItems([doneButton], animated: false)
                cell.valueTextField.inputAccessoryView = toolBar
                cell.valueTextField.inputView = multiplePicker
            default:
                print("default")

        }
        cell.backgroundColor = UIColor.clear
        cell.property.text = properties[indexPath.item]
        cell.isUserInteractionEnabled = true
        cell.valueTextField.isUserInteractionEnabled = true
        cell.valueTextField.delegate = self
        cell.valueTextField.tag = indexPath.item
        toolBar = UIToolbar()
        toolBar.sizeToFit()
        reminderCells[indexPath.item] = cell
        return cell
    }

    // data method to return the number of column shown in the picker.
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    // data method to return the number of row shown in the picker.
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        print(myValues.count)
        return myValues.count
    }

    // delegate method to return the value shown in the picker
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return myValues[row] as? String
    }

    // delegate method called when the row was selected.
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        reminderCells[i].valueTextField.text = myValues[row] as? String
    }
}

Изменить Сделано в cellForRowAt послеОтвет Мэтта (на этот раз я указываю тип во время компиляции):

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

    switch properties[indexPath.item]{
        case "Diet","Body Type":
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell
            let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
            toolBar.setItems([doneButton], animated: false)
            cell.valueTextField.inputAccessoryView = toolBar
            cell.valueTextField.inputView = myUIPicker

            cell.backgroundColor = UIColor.clear
            cell.property.text = properties[indexPath.item]
            cell.isUserInteractionEnabled = true
            cell.valueTextField.isUserInteractionEnabled = true
            cell.valueTextField.delegate = self
            cell.valueTextField.tag = indexPath.item
            toolBar = UIToolbar()
            toolBar.sizeToFit()
            reminderCells[indexPath.item] = cell
            return cell
        case "Looking For","Ethnicity":
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell2
            multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
            multiplePicker.myValues = ethnicityOpts as! [String]
            let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
            toolBar.setItems([doneButton], animated: false)
            cell.valueTextField.inputAccessoryView = toolBar
            cell.valueTextField.inputView = multiplePicker

            cell.backgroundColor = UIColor.clear
            cell.property.text = properties[indexPath.item]
            cell.isUserInteractionEnabled = true
            cell.valueTextField.isUserInteractionEnabled = true
            cell.valueTextField.delegate = self
            cell.valueTextField.tag = indexPath.item
            toolBar = UIToolbar()
            toolBar.sizeToFit()
            reminderCells[indexPath.item] = cell
            return cell
        default:
            print("default")

    }

1 Ответ

0 голосов
/ 20 мая 2018

Эта идея из вашего dequeue вызова в cellForRowAt гениальна и естественна, но незаконна:

as! cellTypes[indexPath.row]

Swift не позволит вам привести (as!) к типу, которыйне указано до времени выполнения.Это статический язык, а не динамический язык.Тип должен быть литеральным типом, указанным во время компиляции.

Вам просто нужно разделить вашу реализацию cellForRowAt на два совершенно разных случая переключения, один для строк 0 и 1,и один для строк 2 и 3, и делать разные dequeue для каждого, каждый из которых объявляет и указывает свою собственную локальную cell переменную с приведением as! FilterTableViewCell или as! FilterTableViewCell2 буквально - иисходя из этого, отдельно , внутри каждого случая.

Вы не можете объединить два случая, как это пытается сделать ваш элегантно выглядящий код, потому что только в контексте, где cell напечатано буквально в качестве FilterTableViewCell или FilterTableViewCell2 можно получить доступ к свойствам, относящимся к соответствующему типу.

Что касается этого выражения:

var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),
                     FilterTableViewCell2(),FilterTableViewCell2()]

... проблема заключается в том, что Swiftможно только сделать вывод, что это должен быть массив UITableViewCell, который не имеет свойств FilterTableViewCell.

Вы можете обойти это, определив третий тип, например FilterTableViewCellParent, чтобы действовать в качестве общего суперкласса для FilterTableViewCell и FilterTableViewCell2 и предоставлять it их общие свойства, которые они оба могут наследовать;reminderCells может быть массивом FilterTableViewCellParent, и вы сможете получить доступ к свойствам через его элемент.(Или, конечно, вы можете сделать FilterTableViewCell суперклассом FilterTableViewCell2 или наоборот , и, таким образом, сделать это только с двумя типами.)

Но лично я думаю, что вы должны отказаться от своих попыток быть "элегантный »и просто делайте все совершенно раздельно в двух случаях переключения, даже за счет некоторого повторения.Иногда нужно просто запрограммировать, как Супермен попадает в штаны;он может быть Суперменом, но ему все равно приходится вставать на одну ногу за раз.

...