Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 从UIAlertController重新加载tableView数据不工作_Ios_Swift_Uitableview - Fatal编程技术网

Ios 从UIAlertController重新加载tableView数据不工作

Ios 从UIAlertController重新加载tableView数据不工作,ios,swift,uitableview,Ios,Swift,Uitableview,从UIAlertController刷新tableView数据时遇到问题。 该代码用于测验式应用程序,此页面允许用户选择 主题以及一些其他选项(参见屏幕截图)。有一个 “仅显示未看到的问题”旁边的重置按钮,该按钮将触发 UIAlertController。但是,单击此警报中的重置操作 更新数据库,但不更新tableView。数据库是 绝对更新,就像我回到一个页面,然后重新访问 在tableView中,主题单元格中未显示的问题值将更新。我意识到有相当多的 这里有这些类型的问题,但我恐怕没有一个常见

UIAlertController
刷新tableView数据时遇到问题。 该代码用于测验式应用程序,此页面允许用户选择 主题以及一些其他选项(参见屏幕截图)。有一个 “仅显示未看到的问题”旁边的重置按钮,该按钮将触发
UIAlertController
。但是,单击此警报中的重置操作 更新数据库,但不更新tableView。数据库是 绝对更新,就像我回到一个页面,然后重新访问 在tableView中,主题单元格中未显示的问题值将更新。我意识到有相当多的 这里有这些类型的问题,但我恐怕没有一个常见的解决办法 工作

额外信息:

  • tableView通过一系列定制功能进行定制 UITableViewCells
  • 数据通过FMDB从SQLite数据库加载
  • 重置时,UIAlertController从NSN通知触发 按钮被点击
到目前为止,我已经:

  • 已检查数据源和委托设置是否正确、以编程方式和 在IB中,使用
    打印(self.tableView.datasource)
    等确认
  • 确认
    reloadData()
    正在启动
  • 将主线程用于
    reloadData()
下面摘录TableViewController代码和屏幕截图

override func viewDidLoad() {
    super.viewDidLoad()

    self.tableView.dataSource = self
    self.tableView.delegate = self

    //For unique question picker changed
    NotificationCenter.default.addObserver(self, selector: #selector(SubjectsTableViewController.reloadView(_:)), name:NSNotification.Name(rawValue: "reload"), object: nil)

    //For slider value changed
    NotificationCenter.default.addObserver(self, selector: #selector(SubjectsTableViewController.updateQuantity(_:)), name:NSNotification.Name(rawValue: "updateQuantity"), object: nil)

   //Trigger UIAlertController
    NotificationCenter.default.addObserver(self, selector: #selector(SubjectsTableViewController.showAlert(_:)), name:NSNotification.Name(rawValue: "showAlert"), object: nil)

}

// MARK: - Table view data source

///////// Sections and Headers /////////

override func numberOfSections(in tableView: UITableView) -> Int {
    return 3
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
    let subjectHeaderCell = tableView.dequeueReusableCell(withIdentifier: "sectionHeader")
    switch section {
    case 0:
        subjectHeaderCell?.textLabel?.text = "Select Subjects"
        return subjectHeaderCell
    case 1:
        subjectHeaderCell?.textLabel?.text = "Options"
        return subjectHeaderCell
    case 2:
        subjectHeaderCell?.textLabel?.text = ""
        return subjectHeaderCell
    default:
        subjectHeaderCell?.textLabel?.text = ""
        return subjectHeaderCell

    }
}

//Header heights
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
    return 34.0
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0:
        return SubjectManager.subjectWorker.countSubjects()
    case 1:
        return 2
    case 2:
        return 1
    default:
        return 0
    }
}


///////// Rows within sections /////////

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    switch (indexPath.section) {
    case 0:
        //Configure subjectCell //
        let cellWithSubject = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell

        //Curve corners
        cellWithSubject.subjectCellContainer.layer.cornerRadius = 2
        cellWithSubject.subjectCellContainer.layer.masksToBounds = true

        //Set subject title label
        cellWithSubject.subjectTitleLabel.text = SubjectManager.subjectWorker.collateSubjectTitles()[indexPath.row]

        //Available questions for subject label
        questionCountForSubjectArray = QuestionManager.questionWorker.countQuestions()
        cellWithSubject.subjectAvailableQuestionsLabel.text = "Total questions available: \(questionCountForSubjectArray[indexPath.row])"

        //Get questions in subject variables
        seenQuestionsForSubjectArray = QuestionManager.questionWorker.countOfQuestionsAlreadySeen()

        //New questions available label
        unseenQuestionsForSubjectArray.append(questionCountForSubjectArray[indexPath.row] - seenQuestionsForSubjectArray[indexPath.row])
        cellWithSubject.newQuestionsRemainingLabel.text = "New questions remaining: \(unseenQuestionsForSubjectArray[indexPath.row])"

        return cellWithSubject

    case 1:
        switch (indexPath.row) {
        case 0:
        //Configure uniqueQuestionCell //
            let cellWithSwitch = tableView.dequeueReusableCell(withIdentifier: "uniqueQuestionCell", for: indexPath) as! UniqueQuestionTableViewCell

        //Curve corners
            cellWithSwitch.uniqueQuestionContainer.layer.cornerRadius = 2
            cellWithSwitch.uniqueQuestionContainer.layer.masksToBounds = true

            return cellWithSwitch

        case 1:
            //Configure sliderCell //
            let cellWithSlider = tableView.dequeueReusableCell(withIdentifier: "questionPickerCell", for: indexPath) as! QuestionPickerTableViewCell

            //Curve corners
            cellWithSlider.pickerCellContainer.layer.cornerRadius = 2
            cellWithSlider.pickerCellContainer.layer.masksToBounds = true

            //Set questions available label
            cellWithSlider.questionsAvailableLabel.text = "Available: \(sumQuestionsSelected)"

            //Configure slider
            cellWithSlider.questionPicker.maximumValue = Float(sumQuestionsSelected)
            cellWithSlider.questionPicker.isContinuous = true
            //Logic for if available questions changes - updates slider stuff
            if questionQuantityFromSlider > sumQuestionsSelected {
                questionQuantityFromSlider = sumQuestionsSelected
                cellWithSlider.questionsToStudy = questionQuantityFromSlider
                cellWithSlider.questionsChosenLabel.text = "Questions to study: \(questionQuantityFromSlider)"
            } else { questionQuantityFromSlider = cellWithSlider.questionsToStudy
            }

            //Configure questions chosen label:
            if questionsToStudyDict.isEmpty {
                cellWithSlider.chooseSubjectsLabel.text = "Choose a subject"
                cellWithSlider.questionsChosenLabel.text = "Questions to study: 0"
            } else {
                cellWithSlider.chooseSubjectsLabel.text = ""
            }
            return cellWithSlider

        default:
            return UITableViewCell()
        }
    case 2:
        print("cellForRowAt case 2")
        //Configure beginCell //
        let cellWithStart = tableView.dequeueReusableCell(withIdentifier: "beginCell", for: indexPath) as! BeginStudyTableViewCell

        //Curve corners
        cellWithStart.startContainer.layer.cornerRadius = 2
        cellWithStart.startContainer.layer.masksToBounds = true

        return cellWithStart

    default:
        return UITableViewCell()
    }
}

//Row heights
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    switch (indexPath.section) {
    case 0:
        return 120.0
    case 1:
        switch (indexPath.row) {
        case 0:
            return 60.0
        case 1:
            return 100.0
        default:
            return 44.0
        }
    case 2:
        return 100.0
    default:
        return 44.0
    }
}


override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    if indexPath.section == 2 || indexPath.section == 0 {
        return true
    } else {
        return false
    }
}

override func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
    if indexPath.section == 2 && selectedRowsDict.isEmpty != true && questionQuantityFromSlider > 0 {
        let cellToBegin = tableView.cellForRow(at: indexPath) as! BeginStudyTableViewCell

        cellToBegin.startContainer.backgroundColor = UIColor.lightGray
    }
}

override func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
    if indexPath.section == 2 {
        let cellToBegin = tableView.cellForRow(at: indexPath) as! BeginStudyTableViewCell

        cellToBegin.startContainer.backgroundColor = UIColor.white
    }
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    switch (indexPath.section) {
        case 0:
        //Set checkbox to ticked image
        let cellWithSubject = tableView.cellForRow(at: indexPath) as! SubjectTableViewCell
        cellWithSubject.subjectSelectedImageView.image = UIImage(named: "CheckboxTicked")

        //Determine questions available for subject depending on unseen value
        if showUnseenQuestions == true {
            questionsToStudyDict[indexPath.row] = unseenQuestionsForSubjectArray[indexPath.row]
        } else {
            questionsToStudyDict[indexPath.row] = questionCountForSubjectArray[indexPath.row]
        }

        //Sum questions available
        sumQuestionsSelected = Array(questionsToStudyDict.values).reduce(0, +)

        //Reload table to pass this to questions available label in UISlider cell and reselect selected rows
        let key: Int = indexPath.row
        selectedRowsDict[key] = indexPath.row
        self.tableView.reloadData()
        if selectedRowsDict.isEmpty == false {
            for (keys,_) in selectedRowsDict {
            let index: IndexPath = NSIndexPath(row: selectedRowsDict[keys]!, section: 0) as IndexPath
            tableView.selectRow(at: index, animated: false, scrollPosition: .none)
            }
        }
    case 1:
        break
    case 2:
        if selectedRowsDict.isEmpty != true && questionQuantityFromSlider > 0 {
            self.performSegue(withIdentifier: "showStudyQuestion", sender: self)
        } else {
            print("Segue not fired")
        }
    default:
        break
    }
}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    if indexPath.section == 0 {

        //Set checkbox to unticked image
        let cellWithSubject = tableView.cellForRow(at: indexPath) as! SubjectTableViewCell
        cellWithSubject.subjectSelectedImageView.image = UIImage(named: "Checkbox")

        //Remove questions available for unselected subject from questions dictionary
        questionsToStudyDict[indexPath.row] = nil

        //Update sum of questions selected
        sumQuestionsSelected = Array(questionsToStudyDict.values).reduce(0, +)

        //Reload table to pass this to questions available label in UISlider cell and reselect selected rows
        let key: Int = indexPath.row
        selectedRowsDict[key] = nil
        self.tableView.reloadData()
        if selectedRowsDict.isEmpty == false {
            for (keys,_) in selectedRowsDict {
                let index: IndexPath = NSIndexPath(row: selectedRowsDict[keys]!, section: 0) as IndexPath
                tableView.selectRow(at: index, animated: false, scrollPosition: .none)
            }
        }
    }
}

func reloadView(_ notification: Notification) {

    //Change bool value
    showUnseenQuestions = !showUnseenQuestions

    //For keys in dict, update values according to showUnseenQuestion value
    if showUnseenQuestions == true {
    for (key,_) in questionsToStudyDict {
        questionsToStudyDict[key] = unseenQuestionsForSubjectArray[key]
        }
    } else {
            for (key,_) in questionsToStudyDict {
                questionsToStudyDict[key] = questionCountForSubjectArray[key]
        }
    }

    //Re-run sum dict function
    sumQuestionsSelected = Array(questionsToStudyDict.values).reduce(0, +)

    //Finally reload the view and reselect selected rows
    let selectedRowsIndexes = tableView.indexPathsForSelectedRows
    self.tableView.reloadData()
    if selectedRowsIndexes != nil {
        for i in (selectedRowsIndexes)! {
            tableView.selectRow(at: i, animated: false, scrollPosition: .none)
        }
    }
}

func updateQuantity(_ notification: Notification) {

    //Reload the view and reselect selected rows
    let selectedRowsIndexes = tableView.indexPathsForSelectedRows
    self.tableView.reloadData()
    if selectedRowsIndexes != nil {
        for i in (selectedRowsIndexes)! {
            tableView.selectRow(at: i, animated: false, scrollPosition: .none)
        }
    }
}

func showAlert(_ notification: Notification) {
    let alertController = UIAlertController(title: "Reset Seen Questions", message: "Are you sure you want to reset all questions to unseen?", preferredStyle: .alert)
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { action in
        // ...
    }
    alertController.addAction(cancelAction)

    let OKAction = UIAlertAction(title: "Reset", style: .default, handler:{(action:UIAlertAction) -> Void in
        QuestionManager.questionWorker.resetHasSeenValues()
        self.reloadData()
        print("reloadData fired")
    })

    alertController.addAction(OKAction)

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

}

func reloadData() {
    DispatchQueue.main.async(execute: {
        self.tableView.reloadData()
    })
}

在主队列中添加
self.reloadData()
。出口变化应始终保持在主螺纹内

 let OKAction = UIAlertAction(title: "Reset", style: .default, handler:{(action:UIAlertAction) -> Void in
            QuestionManager.questionWorker.resetHasSeenValues()
            DispatchQueue.main.async {
             self.tableView.reloadData()
            }
            print("reloadData fired")
})

进一步的调试表明,
cellForRowAt
方法中未正确填充subjectarray未查看的问题。我解决了这个问题,也解决了
reloadData()
问题。谢谢大家的帮助。

如前所述,我已经尝试过了,但运气不佳。无论如何谢谢你!您写道“数据库肯定会更新,就像我返回一个页面,然后重新访问tableView一样,主题单元格中未看到的问题值也会更新。”。您的
QuestionManager
是否异步重置所看到的值?@Nathan我不完全确定
QuestionManager
是一个我用来保存一系列函数的单例。我已经用
countofQuestionsReadySeen()
函数更新了原始帖子,该函数应该在执行
reloadData()
时执行,如果这样有帮助的话?更有趣的是看看
QuestionManager.questionWorker.resetHasSeenValues()
做了什么。也许这就是你可以开始调试的地方?@Nathan-抱歉,我本来是想给你发这个的!OP更新。我刚刚检查了一下-
resetHasSeenValues()。看来我需要研究一下同步/异步操作……我相信您,数据库已经正确更新了。但我不确定数据库是否及时更新。我试着为您的示例制作一个简化版本(没有数据库),一切都正常。这就是为什么我假设存在同步/异步问题。你可以找到我的密码。
 let OKAction = UIAlertAction(title: "Reset", style: .default, handler:{(action:UIAlertAction) -> Void in
            QuestionManager.questionWorker.resetHasSeenValues()
            DispatchQueue.main.async {
             self.tableView.reloadData()
            }
            print("reloadData fired")
})