показывает ошибку, так как должен соответствовать протоколу - PullRequest
0 голосов
/ 03 сентября 2018

Это мой код: -

Модель: -

class QuestionListModel: NSObject {

    var optionsModelArray:[OptionsModel] = []

     var question:String!

    init(dictionary :JSONDictionary) {

        guard   let question = dictionary["question"] as? String

             else {
                return

        }

        if let options = dictionary["options"] as? [String]{
            print(options)

            print(options)

            for values in options{

                print(values)

                let optionmodel = NH_OptionsModel(values: values)
                self.optionsModelArray.append(optionmodel)

                         }

        }
              self.question = question
         //   print(self.dataListArray33)
                   }
}

optionModel: -

class OptionsModel: NSObject {
 var values:String?
         init(values:String) {

           self.values = values
           print( self.values)

        }
 }

в viewmodel: -

var questionsModelArray:Array<NH_QuestionListModel>? = []
     init(withdatasource  newDatasourceModel:NH_QuestionDataSourceModel) {
            datasourceModel = newDatasourceModel

            print(datasourceModel.dataListArray?.count)

             self.questionsModelArray = datasourceModel.dataListArray

            print(self.questionsModelArray)

            print(datasourceModel.dataListArray)
        }


               func numberOfSections() -> Int{

               return (self.questionsModelArray?.count)!

                }

                func titleForHeaderInSection(atindexPath indexPath: IndexPath) -> QuestionListModel {

                    return self.questionsModelArray![indexPath.row]

                }

            func numberOfRowsInSection(indexPath:IndexPath) -> Int {

                if  let questionModel = self.questionsModelArray?[indexPath.section]{

                    return questionModel.optionsModelArray.count

               }

              else{
                  return 0

           }                   
           }


            func datafordisplay(atindex indexPath: IndexPath) -> OptionsModel{

               let questionModel = self.questionsModelArray?[indexPath.section]

                           return questionModel!.optionsModelArray[indexPath.row]

            }

А в ViewController: -

func numberOfSections(in tableView: UITableView) -> Int {

        return questionViewModel.numberOfSections()

    }


   func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {


        //  let headercell = Bundle.main.loadNibNamed("HeaderCell", owner: self, options: nil)?.first as! NH_questionheader


        let identifier = "HeaderCell"

        var headercell: NH_questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader

        if headercell == nil {
            tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: identifier)
            headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
        }

        headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atindexPath:section))

        return headercell
    }



    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        return 150

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: IndexPath) -> Int {

       return questionViewModel.numberOfRowsInSection(indexPath: section)
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = "Cell"
        var cell: CellTableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell

        if cell == nil {
            tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
            cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell
        }
        cell.contentView.backgroundColor = UIColor.clear

       cell.setOptions(Options1: questionViewModel.datafordisplay(atindex: indexPath))

        print("Section \(indexPath.section), Row : \(indexPath.row)")            

        return cell

    }

мой файл json: -

{
    "data":[
              {
              "question": "Gender",
              "options": ["Male","Female"]

              },
              {
              "question": "How old are you",
              "options": ["Under 18","Age 18 to 24","Age 25 to 40","Age 41 to 60","Above 60"]
            }, {
            "question": "I am filling the Questionnaire for?",
            "options": ["Myself","Mychild","Partner","Others"]
            }
              ]      
}

Это мои данные. Так что мне нужно отобразить вопросы в заголовке и опции в ячейке для индекса. Но показывается как ошибка, так как UITableview должен соответствовать протоколу UITableviewDataSource.

Также показывает ошибку как индекс вне диапазона. Как сделать .....

Ответы [ 5 ]

0 голосов
/ 03 сентября 2018

Чтобы достичь того, что вы хотите, вы должны установить свой VC как делегат и источник данных вашей таблицы.

Вариант 1, сделать это динамически:

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.delegate = self
    self.tableView.dataSource = self
}

Вариант 2 из вашей раскадровки (пример ниже):

enter image description here

После этого вы должны использовать следующие функции источника данных UITableView:

// return number of questions
func numberOfSections(in tableView: UITableView) -> Int

// return number of options per question (indicated by section)
func tableView(UITableView, numberOfRowsInSection: Int) -> Int
0 голосов
/ 03 сентября 2018

ваш контроллер представления не может найти источник данных и делегировать представление таблицы. убедитесь, что вы назначили источник данных и делегировали

self.yourtableview.delegate = self
self.yourtableview.dataSource = self

, а также убедитесь, что ваш контроллер также наследует UITableViewDelegate и UITableViewDataSource, как это

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
0 голосов
/ 03 сентября 2018

Эта ошибка обычно возникает, когда вам не удается реализовать требуемые методы протокола. В этом случае методы будут:

  1. cellForRowAt
  2. numberOfRowsInSection

Поскольку они уже реализованы в вашем контроллере представления, возможно, вам не удалось установить источник данных для табличного представления.

Обратитесь к этому https://developer.apple.com/documentation/uikit/uitableviewdatasource

0 голосов
/ 03 сентября 2018

Вы не правильно объявили функцию numberOfRowsInSection; section - это Int, а не IndexPath. В результате вы не реализовали обязательные функции UITableViewDataSource.

Вы хотите:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     return questionViewModel.numberOfRowsIn(section: section)
}

При соответствующем изменении модели вашего вида:

 func numberOfRowsIn(section:Int) -> Int {
    return self.questionsModelArray?[section].optionsModelArray.count ?? 0

 }

Я бы также предложил вам пересмотреть использование неявно развернутых опций и принудительное развертывание; это просто запрос на сбои.

Например, нет никакой причины для свойства question QuestionListModel быть String!; просто объявите его как String и отключите инициализатор. А еще лучше: используйте Codable, чтобы создать свою модель из JSON и избавиться от всего этого кода.

Вы также можете устранить развертывание силы в numberOfSections:

func numberOfSections() -> Int {
    return self.questionsModelArray?.count ?? 0
}

Я бы также предложил вам сделать QuestionListModel структурой, а не NSObject подклассом.

На вашем месте я бы рефакторировал, чтобы удалить модель представления, в этом случае она добавляет ненужную сложность, и для десериализации JSON используйте Codable:

struct Questions: Codable {

    enum CodingKeys: String, CodingKey {
        case questions = "data"
    }

    var questions: [Question]
}

struct Question: Codable {
    var question: String
    var options: [String]
}

Ваш контроллер представления становится намного проще:

class ViewController: UIViewController, UITableViewDatasource {

    var questionData: Questions?

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: "HeaderCell")
        tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
        // You don't show how you load your JSON, but assuming you have it in an instance of `Data` called `jsonData`:
        do {
            self.questionData = try JSONDecoder().decode(Questions.self, from: jsonData)
        } catch { 
            print("Error decoding JSON: \(error.localizedDescription)")
        }
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {

        let identifier = "HeaderCell"

        guard let questionData = self.questionData,
          let headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader  else {
            return nil
        }

        headercell.label.text = questionData.questions[section].question
        return headercell
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 150
}

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.questionData?.questions[section].options.count ?? 0
    } 

    func numberOfSections(in tableView: UITableView) -> Int {

        return self.questionData?.questions.count ?? 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = "Cell"
    // Note, I have used force unwrapping and a forced downcast here as if either of these lines fail you have a serious problem and crashing is the simplest way of finding it during development
        let option =  self.questionData!.questions[indexPath.section].options[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath ) as! CellTableViewCell
        cell.contentView.backgroundColor = .clear
        cell.label.text = option
    return cell

    }

}

Если у вас работает этот базовый подход, вы можете попробовать добавить модель представления, если хотите.

0 голосов
/ 03 сентября 2018

Я думаю, что вы не назначаете источник данных для вашего контроллера представления. Поэтому, пожалуйста, назначьте его в вашем ViewDidLoad контроллере вида

 override func viewDidLoad() {
    super.viewDidLoad()
    self.yourtableview.delegate = self
    self.yourtableview.dataSource = self
    // Do any additional setup after loading the view.
}
...