TableView 仅在屏幕旋转后更新

TableView Only Updates after Screen Rotates

Image of the tableview

我有一个 table 视图,每个单元格中都有一个集合视图,所有视图都链接到一个数组。每个集合视图都有标签,所以当我从一开始就在数组中添加内容时,所有 table 视图单元格和集合视图单元格都会正确显示在应用程序中。但是当我在应用程序本身的数组中添加一个元素时(我有第二个视图控制器可以执行此操作),它可以工作但是新的 table 视图单元格仅在屏幕旋转后出现(真的很奇怪) .我尝试在第二个视图控制器中添加一个带有 table 视图的视图控制器对象,我将一个元素添加到数组中。然后在 ViewWillDisappear 的第二个视图控制器中,我通过该对象重新加载数据(),如下所示:

var vc : ViewController? = ViewController()

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    vc?.listOfActs.reloadData()
}

但这会导致 EXC_BAD_INSTRUCTION

然后我尝试在带有 table 视图的视图控制器的 prepareForSegue 中添加 self.listOfActs.reloadData() ,这样我就可以看到它至少在某个时间点刷新数据但是当我第二次点击添加场景时,即使这样也不起作用。

更新:新 MainViewController

这是带有 table 视图的第一个新视图控制器。我重命名了它并实现了添加到数组和重新加载的方法。如果我在 reloadData 上使用 if let ,它会起作用,但我又回到原点,它只在我旋转屏幕时更新。当我摆脱 if let 以便它实际上可以尝试更新 table 视图时,它给了我一个 Fata 错误:unwrapping unexpectedly found a nil.

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

//The Table View

@IBOutlet var AddActButton: UIButton!

@IBOutlet weak var listOfActs: UITableView!

var sectionTapped : Int?
var indexitemTapped : Int?

override func viewDidLoad() {

    super.viewDidLoad()

    listOfActs.delegate = self

    listOfActs.dataSource = self

}

//Table View Functions

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

    return actsCollection.count
}

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

    return 1
}

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "actCell", for: indexPath) as! ActCell

    cell.setCollectionViewDataSourceDelegate(self, forSection: indexPath.section)

    return cell
}

//Add To Table View

func addObjects(appendage: Act) {
    actsCollection.append(appendage)

    if let shit = listOfActs {

        shit.reloadData()

    }
}

//Header Cell

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

    let cellHeader = tableView.dequeueReusableCell(withIdentifier: "headerCell") as! HeaderCell

    cellHeader.headerName.text = actsCollection[section].actName

    return cellHeader
}

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

}

//Scene Collection in Act Cell

extension MainViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return actsCollection[collectionView.tag].actScenes.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "sceneCell", for: indexPath) as! SceneCell

    cell.sceneTitle.text = actsCollection[collectionView.tag].actScenes[indexPath.item].sceneTitle

    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    sectionTapped = collectionView.tag
    indexitemTapped = indexPath.item

    performSegue(withIdentifier: "showDetail", sender: self)

}

//Segue Prepare

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {

        let detailsVC = segue.destination as! SceneDetailController

        detailsVC.textToAppearInSceneName = actsCollection[sectionTapped!].actScenes[indexitemTapped!].sceneTitle

    }
}

}

更新:新的第二个视图控制器,添加到数组的那个。

class AddActController: UIViewController, UITextFieldDelegate {

@IBOutlet var sceneLiveName: UILabel!
@IBOutlet var sceneNameTextField: UITextField!

@IBOutlet var sceneDescriptionTextField: UITextField!

@IBOutlet var AddSceneButton: UIButton!

@IBOutlet var cardBounds: UIView!

var newName: String? = ""

@IBOutlet var cardShadow: UIView!

var shit = MainViewController()

override func viewDidLoad() {
    super.viewDidLoad()

    sceneNameTextField.delegate = self

    AddSceneButton.alpha = 0.0

    cardBounds.layer.cornerRadius = 20.0
    cardShadow.layer.shadowRadius = 25.0
    cardShadow.layer.shadowOpacity = 0.4


    // Do any additional setup after loading the view.
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    UIView.animate(withDuration: 0.2){
        self.AddSceneButton.alpha = 1.0
    }
}


@IBAction func exitButton(_ sender: UIButton) {
    dismiss(animated: true, completion: nil)
}

@IBAction func addSceneButton(_ sender: UIButton) {
    if newName == "" {
        sceneLiveName.text = "Enter Something"
        sceneNameTextField.text = ""
    }
    else {
        let appendAct: Act = Act(actName: newName!, actTheme: "Action", actScenes: [Scene(sceneTitle: "Add Act", sceneDescription: "")])
        shit.addObjects(appendage: appendAct)

        dismiss(animated: true, completion: nil)
    }
}

//MARK: textField

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let text: NSString = (sceneNameTextField.text ?? "") as NSString
    let resultString = text.replacingCharacters(in: range, with: string)
    sceneLiveName.text = resultString
    newName = String(describing: (sceneLiveName.text)!.trimmingCharacters(in: .whitespacesAndNewlines))
    return true
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    sceneNameTextField.resignFirstResponder()
    return true
}

/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

这是包含自己的集合视图的 uitableviewcell 的 class。

class ActCell: UITableViewCell {

@IBOutlet fileprivate weak var sceneCollection: UICollectionView!

}

extension ActCell {
    func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forSection section: Int) {

    sceneCollection.delegate = dataSourceDelegate
    sceneCollection.dataSource = dataSourceDelegate
    sceneCollection.tag = section
    sceneCollection.reloadData()
    }

}

这里是包含用户数据的模型,包括行为和场景。

struct Scene {
var sceneTitle: String
var sceneDescription: String
//var characters: [Character]
//var location: Location
}

struct Act {
    var actName: String
    var actTheme: String
    var actScenes : [Scene] = []
}

var actsCollection : [Act] = [
    Act(actName: "dfdsfdsfdsf", actTheme: "Action", actScenes: [Scene(sceneTitle: "Example Act", sceneDescription: "")])
]

非常感谢任何帮助。谢谢大家。

因此,如果我没记错的话,我相信 viewDidLoad 方法会在屏幕旋转期间被调用。所以这解释了为什么它会在此期间更新。现在为了让它在不旋转设备的情况下更新,我会在 notificationCenter 中添加一个观察者来观察 tableView 的任何更新,然后调用 #selector 来执行 reloadData().所以这是一个例子。在 viewDidLoad 方法中添加

NotificationCenter.default.addObserver(self, selector: #selector(refreshTable), name: NSNotification.Name(rawValue: "load"), object: nil)

然后添加方法refreshTable()

func refreshTable() {
listOfActs.reloadData()
}

这基本上就是我处理保持 tableView 刷新的方式。

好吧 - viewDidLoad 仅在控制器第一次加载他的视图时加载(不确定旋转)。

如果您确实需要 - 您可以在 viewWillAppear 中重新加载 tableView - 但我不会这样做。

而不是

actsCollection.append(appendAct)
dismiss(animated: true, completion: nil)

在第一个控制器上创建一个方法,例如 addObjectToList(appendAct),在该方法中,只需轻松地将对象附加到列表数组并在添加后重新加载 tableView

只有当您真正向列表中添加内容时才会重新加载tableView,而不是每次出现控制器时,您也不需要通知观察器。

编辑 - 更新

这是什么?

if newName == "" {
    sceneLiveName.text = "Enter Something"
    sceneNameTextField.text = ""
}
else {
    let appendAct: Act = Act(actName: newName!, actTheme: "Action", actScenes: [Scene(sceneTitle: "Add Act", sceneDescription: "")])
    shit.addObjects(appendage: appendAct)

    dismiss(animated: true, completion: nil)
}

我的意思是 - shit.AddObjects 是什么? Shit 被定义为 tableView - 但你必须在你的控制器实例上调用这个方法。

另一件事 - 将您的设置从部分 == 1 行的项目数更改为一个部分,行数 == 项目数。 :)