【问题标题】:Connecting TableView within ViewController - self.tableView.reloadData() not working in Swift在 ViewController 中连接 TableView - self.tableView.reloadData() 在 Swift 中不起作用
【发布时间】:2015-12-06 02:47:54
【问题描述】:

我是一个学习 iOS 和 Swift 的新手,所以提前道歉。目前我正在尝试在 viewController 中设置一个 tableView 并在屏幕的一部分的单元格中显示数据。我当前的问题似乎是在为 numberOfRowsInSection() 调用 viewDidLoad() 中的 Alamofire HTTP 请求后重新加载 tableView 数据。代码如下:

import UIKit
import Alamofire
import SwiftyJSON

class CourseDetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var titleLabel: UILabel?
    @IBOutlet weak var creditsLabel: UILabel?
    @IBOutlet weak var descriptionLabel: UILabel?

    @IBOutlet weak var tableView: UITableView!

    var detailCourse: Course? {
        didSet {
            configureView()
        }
    }

    var course: Course!

    func configureView() {
        self.title = detailCourse?.abbr
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SectionCell")
        tableView.delegate = self
        tableView.dataSource = self

        if let theCourse: Course = self.detailCourse as Course! {

            var abbr: String = theCourse.abbr!

            APIService.getCourseByAbbr(abbr) { (data) -> Void in
                self.course = Course(courseJSON: data)

                // Set labels
                self.titleLabel?.text = self.course.title!
                self.descriptionLabel?.text = self.course.description!

                if let creditsArray = self.course.credits {
                    let minimumCredit = creditsArray[0] as Int
                    self.creditsLabel?.text = String(minimumCredit)
                }

                self.tableView.reloadData()
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return course.sections.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // Configure the cell...
        let cell = tableView.dequeueReusableCellWithIdentifier("SectionCell", forIndexPath: indexPath) as! SectionTableViewCell
        let sectionCell = course.sections[indexPath.row]

        cell.termLabel?.text = sectionCell.term
        cell.timeLabel?.text = sectionCell.startTime
        cell.instructorLabel?.text = sectionCell.instructor

        return cell
    }
}

当我运行时,我收到以下错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

我认为原因可能是我在viewController中设置了tableView不正确。

对于完整的项目,这里是 repo 的链接:https://github.com/classmere/app/tree/develop

【问题讨论】:

  • 您在哪一行收到错误消息?还要确保在重新加载 tableView 时您的“numberOfRowsInSection”是正确的。
  • @air6199 返回 course.sections.count
  • 现在把那行注释掉,然后用“return 0”替换它,会发生什么?我试图访问您的项目,但它缺少此文件。
  • 我想我已经找出问题的根源了...... self.detailCourse 和 self.course 都是零。他们从来没有被分配任何东西。您的“if let theCourse: ...”语句永远不会正确,因此它无法运行。这会检查它是否确实存在,但它返回 false,因为它当前为 nil。不完全确定我是否正确,但看起来就是这样。
  • @air6199 对于您的第一条评论,它会运行,但不会显示任何数据。对于您的第二条评论,我认为它们为零,因为它们没有机会被初始化,因为 APIService 中的代码没有完成及时返回对象以供 tableView 方法使用。我相信这可能是因为 self.tableView.reloadData() 指向不正确,因为 viewController 中的 tableView 设置不正确。

标签: ios swift uitableview delegates datasource


【解决方案1】:

问题是你试图解开一个值为 nil 的可选项。当你声明 course 属性时,由于它是可选的,它的初始值为 nil。通常,可选项是用? 声明的,编译器会阻止您访问底层值,而不检查该值是否仍然是nil。但是,在这种情况下,您已将 course 属性设置为预期的可选属性:

var course: Course!

这就像说“我知道course 总是有一个值,永远不会是nil”。但是我们不知道,因为在 Alamofire 回调成功完成之前,它的值是 nil

要解决此问题,首先将course 设为可选标准:

var course: Course?

现在 Xcode 会抱怨你正在访问 course 而不打开它,因为你的 course 声明不再打开它。

通过强制解开 Alamofire 回调中的所有内容来解决此问题:

APIService.getCourseByAbbr(abbr) { (data) -> Void in
    println("APIService()")
    self.course = Course(courseJSON: data)

    // Notice we can access self.course using ! since just assigned it above
    self.titleLabel?.text = self.course!.title!
    self.descriptionLabel?.text = self.course!.description!

    if let creditsArray = self.course!.credits {
        let minimumCredit = creditsArray[0] as Int
        self.creditsLabel?.text = String(minimumCredit)
    }

    self.tableView.reloadData()
}

然后在cellForRowAtIndexPath 中,我们将使用可选链来确保我们只访问course 的属性(如果它们存在):

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    // Configure the cell...
    let cell = tableView.dequeueReusableCellWithIdentifier("SectionCell", forIndexPath: indexPath) as! SectionTableViewCell
    if let section = course?.sections[indexPath.row] {
        cell.termLabel?.text = section.term
        cell.timeLabel?.text = section.startTime
        cell.instructorLabel?.text = section.instructor
    }
    return cell
}

最后,在numberOfRowsForSection 中确保获得实际的节数,而不是总是返回 50。如果 coursenil,我们将使用 nil-coalescing 运算符返回 0:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return course?.sections.count ?? 0
}

这应该可以解决您的问题!

【讨论】:

    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2020-04-16
    • 1970-01-01
    相关资源
    最近更新 更多