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 行的项目数更改为一个部分,行数 == 项目数。 :)
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 行的项目数更改为一个部分,行数 == 项目数。 :)