点击/ reloadData不更改单元格时TableView单元格消失?

Posted

技术标签:

【中文标题】点击/ reloadData不更改单元格时TableView单元格消失?【英文标题】:TableView cells disappearing when tapped / reloadData not changing cells? 【发布时间】:2018-12-29 22:08:21 【问题描述】:

我的 TableView 有两个问题;第一个是每当一个单元格被点击时,它就会消失。单元格的内容视图逐渐消失,并在上下单元格之间留下空隙。我的 didSelect 中没有任何东西可以操纵内容视图。

第二个问题是 reloadData 实际上并没有更新 TableView 的数据。我的 TableView 应该代表一个日历,并且每当调用第二天或前一天按钮(下面代码中的nextDay()prevDay())时,displayDay int 就会更改并调用tableView.reloadData()cellForRowAt 依赖于displayDay 来确定应该在单元格中显示哪一天的事件,因此理论上更改displayDay 会更改单元格的内容。然而,相反,每当按下第二天或前一天的按钮时,单元格的内容根本不会改变(即,它仍然显示第一天的事件)。唯一改变的是如果第一天的事件少于第二天,例如,如果第一天有 3 个事件,第二天有 5 个,表格视图将在第一天的底部显示第二天的最后 2 个事件当天的活动。我的代码在下面

import UIKit
import Foundation
import Alamofire
import SwiftyJSON

class ScheduleTableViewController: UITableViewController 

    var schedule: [DayItem]
    var displayDay: Int
    var numDays: Int?
    @IBOutlet weak var prevDayButton: UIBarButtonItem!
    @IBOutlet weak var nextDayButton: UIBarButtonItem!


    override func viewDidLoad() 
        super.viewDidLoad()
        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
        //schedule = scrapeSchedule()
//        let add = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: nil)//action: #selector(addTapped))
//        navigationController!.toolbarItems = [add]
        let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
        rightSwipe.direction = .right
        view.addGestureRecognizer(rightSwipe)

        let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
        leftSwipe.direction = .left
        view.addGestureRecognizer(leftSwipe)
    

    required init?(coder aDecoder: NSCoder) 
        self.displayDay = 0
        self.schedule = [DayItem]()
        self.numDays = 0
        super.init(coder: aDecoder)
        refresh(self)
    

    @objc func handleSwipes(_ sender: UISwipeGestureRecognizer) 
        if sender.direction == .right 
            if prevDayButton.isEnabled 
                prevDay(self)
             else 
                dismiss(animated: true, completion: nil)
            
         else if sender.direction == .left 
            if nextDayButton.isEnabled 
                nextDay(self)
            
        
    

    func reloadData() 
        tableView.reloadData()
        if schedule.count != 0 
            self.navigationItem.title = self.schedule[self.displayDay].day
        
    

    func configureDayButtons() 
        if schedule.count == 0 
            prevDayButton.isEnabled = false
            nextDayButton.isEnabled = false
         else 
            prevDayButton.isEnabled = true
            nextDayButton.isEnabled = true

            if displayDay == 0 
                prevDayButton.isEnabled = false
            

            if displayDay == numDays! - 1 
                nextDayButton.isEnabled = false
            
        
    

    @IBAction func prevDay(_ sender: Any) 
        if displayDay != 0 
            displayDay -= 1
            configureDayButtons()
            reloadData()
        
    

    @IBAction func nextDay(_ sender: Any) 
        if displayDay != numDays! - 1 
            displayDay += 1
            configureDayButtons()
            reloadData()
        
    
    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    override func numberOfSections(in tableView: UITableView) -> Int 
        // #warning Incomplete implementation, return the number of sections
        return 1
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        // #warning Incomplete implementation, return the number of rows
        if schedule.count != 0 
            return schedule[displayDay].events.count
         else 
            return 0
        
    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let dayItem = schedule[displayDay]
        print("display day = \(displayDay)")
        let eventItem = dayItem.events[indexPath.row]
        let identifier = eventItem.identifier
        let eventOrTimeText = eventItem.event

        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        let label = cell.viewWithTag(1000) as! UILabel
        label.text = eventOrTimeText
        if identifier == "event" || identifier == "eventDDI" 
            label.adjustsFontSizeToFitWidth = true
         else if identifier == "time" || identifier == "location" 
           label.sizeToFit()
        

        return UITableViewCell()

    

    override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) 
        self.tableView(self.tableView, didSelectRowAt: indexPath)
    

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        tableView.deselectRow(at: indexPath, animated: true)
        if schedule[displayDay].events[indexPath.row].information != nil 
            let message = schedule[displayDay].events[indexPath.row].information
            let alert = UIAlertController(title: schedule[displayDay].events[indexPath.row].event, message: message, preferredStyle: .alert)
            let action = UIAlertAction(title: "Close", style: .default, handler: nil)
            alert.addAction(action)
            present(alert, animated: true, completion: nil)
        
    

    @IBAction func close(_ sender: Any) 
        dismiss(animated: true, completion: nil)
    

    @IBAction func refresh(_ sender: Any) 
        scrapeSchedule  schedule in
            self.schedule = schedule!
            DispatchQueue.main.async 
                self.reloadData()
                self.numDays = self.schedule.count
                self.configureDayButtons()
            
        
    

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
       // if schedule.
        if schedule.count != 0 
            let event = schedule[displayDay].events[indexPath.row]
            if event.identifier == "time" && event.event.count > 51 
                return 75
             else if event.identifier == "time" && event.event.count > 31 
                let additionalChars = event.event.count - 31
                var quotient: Float = Float(additionalChars) / 20.0
                quotient = quotient.rounded(.up)
                return CGFloat(quotient * 14 + 40)
            
        
        return 34
    

    func scrapeSchedule(completion: @escaping ([DayItem]?) -> Void) 
        var schedule = [DayItem]()
        URLCache.shared.removeAllCachedResponses()
        Alamofire.request("my api that functions correctly", method: .get).validate().responseData  response in
            switch response.result 
            case .success(let data):
                do 
                    let json = try JSON(data: data)
                    for (index,day):(String, JSON) in json 
                        schedule.append(self.organizeScheduleJSON(dayJSON: day))
                    
                    completion(schedule)
                 catch 
                    completion(nil)
                
            case .failure(let error):
                print(error.localizedDescription)
                completion(nil)
            
        
    

    func organizeScheduleJSON(dayJSON: JSON) -> DayItem 
        var events = [EventItem]()
        for (index,event):(String, JSON) in dayJSON["eventTimes"] 
            if event["information"] != nil 
                events.append(EventItem(event: event["event"].string!, identifier: "eventDDI", information: event["information"].string!))
             else 
                events.append(EventItem(event: event["event"].string!, identifier: "event"))
            
            if event["location"] != nil 
                events.append(EventItem(event: event["location"].string!, identifier: "location"))
            
            if event["times"] != nil 
                var timeArray = event["times"].arrayValue.map($0.stringValue)
                for time in timeArray 
                    events.append(EventItem(event: time, identifier: "time"))
                
            
        
        return DayItem(day: dayJSON["day"].string!, events: events)

    

【问题讨论】:

您的 cellForRow(at:) 看起来不正确。它总是return UITableViewCell() 而不是你配置的cell 解决了它...不知道我是怎么错过的。谢谢! 【参考方案1】:

您的cellForRow(at:) 始终返回一个空的UITableViewCell,而不是您配置的cell 对象。

return UITableViewCell() 替换为return cell

【讨论】:

以上是关于点击/ reloadData不更改单元格时TableView单元格消失?的主要内容,如果未能解决你的问题,请参考以下文章

在选择表格视图单元格时更改按钮的标题

如何在使用 reloadData 时执行单元格选择动画?

使用自我调整大小的单元格后,reloadData 不再起作用

单击单元格时列表视图更改图标

Swift:点击一个单元格时更改所有 UITableViewCells 的文本颜色

iOS - [UITableView reloadData] 重新加载,但不删除旧单元格?