I would like to add two custom cells from different VCs on Swift.
Tab-Navi-List (UIVC) and two other Post Fols, both of which are UIVCs
How should I write it on the list that displays custom cells?
functableView(_tableView:UITableView, numberOfRowsInSection section:Int) - > Int {
return mainArray.count
}
functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath) - >UITableViewCell{
let postcell=tableView.dequeueReusableCell(withIdentifier: "postcell")!
postcell.textLabel?.text=mainArray [indexPath.row]
return postcell
}
If so, I think I can only register one
add
Original VC
class List:UIViewController, UITableViewDataSource, UITableViewDelegate{
varmainArray: String = [ ]
let initArray: String = [ ]
override func viewDidLoad(){
super.viewDidLoad()
tableView.dataSource=self
tableView.delegate=self
// Do any additional setup after the view.
}
@IBOutlet weak variableView:UITableView!
functableView(_tableView:UITableView, numberOfRowsInSection section:Int) - > Int{
return mainArray.count
}
functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath) - >UITableViewCell{
let postcell=tableView.dequeueReusableCell(withIdentifier: "postcell")!
postcell.textLabel?.text=mainArray [indexPath.row]
return postcell
}
functableView(_tableView:UITableView, didSelectRowAtclassName:UITableViewCell){
switchclassName{
case is PostCell:
guardlet viewControlr=storyboard?instantiateViewController(withIdentifier: "Post") as? Postelse{
return
}; navigationController?pushViewController(viewControlr, animated:true)
case is FolderCell:
guard let list = storyboard ?.instantiateViewController(withIdentifier: "List") as ? Listelse{
return
}; navigationController?pushViewController(list, animated:true)
default:
return
}
}
}
Posting VC Post
class Post:UIViewController {
var postString: String=""
@IBOutlet weak var postTextField: UITextField!
override func viewDidLoad(){
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@ IBAction func postBack(_sender:Any){
self.navigationController?popToRootViewController(animated:true)
postTextField.text=postString
guard let list = tabBarController ?.viewControllers ?[0] as ? Listelse{
return
}
let postString=postTextField.text???"
list.tableView?.beginUpdates()
list.tableView?.insertRows(at: IndexPath(row:0, section:0), with:.automatic)
list.tableView?.endUpdates()
}
}
Additional VC Fol
Cells for FolderI don't have the code yet, but it's almost the same as Post, and the only custom cell I'm adding is FolderCell
add
Adding protocol to the list
Protocol 'ListEntryDelegate' cannot be nested inside another declaration
and for extension
Declaration is only valid at file scope
Use of undeclared type 'ListEntryDelegate'
The error appears
Is there any difference?
Note 1
structure ListEntry{
enum CellType: String {
case post="postcell"
case folder="foldercell"
}
/// type
varcellType —CellType
/// text
var text:String
variable array —String
// Increase properties as more information is displayed in one cell
//...
}
Post and Fol to
listView.mainArray.insert(folString, at:0)
I tried to
Cannot convert value of type 'String' to expected argument type 'ListEntry'
will appear
Additional 2
When I tap PostCell, I want to put postString in Post, and when I tap FolderCell, I want to put FolCell array folArray in mainArray of List and transition to Navigation Controller
add
If I press Button on Post, what should I add to the Post Insart when I press Button on Fol?
swift
After reading the updated questions, I understood as follows.
List
(ViewController)UITableView
uses section 0 onlyPlease let me know as soon as possible if there is any misunderstanding.
(It doesn't interfere with the operation, but naming the viewController List
is hard to read because iOS apps don't have it. I think it's better to set it to ListViewController
or at least ListVC
.If you change the class name of the application you are creating, you may have trouble in many non-essential places, so the following is List
(or Post
).
Now, if you want to "show two custom cells" in one UITableView
, you're saying, "I need information somewhere to distinguish between cell types."
mainArray
I will stop preparing a separate array and putting information into it as it becomes more and more complicated and eventually breaks down as the app gets more complicated.
The information corresponding to "one cell" should be represented by "one type."
import Foundation
structureListEntry{
enum CellType: String {
case post="postcell"
case folder="foldercell"
}
/// type
varcellType —CellType
/// text
var text:String
// Increase properties as more information is displayed in one cell
//...
}
The mainArray
in List
should be this ListEntry
array, not the String
array.
class List:UIViewController, UITableViewDataSource, UITableViewDelegate{
varmainArray: ListEntry = [ ]
// let initArray: [String] = [ ]
override func viewDidLoad(){
super.viewDidLoad()
tableView.dataSource=self
tableView.delegate=self
// Do any additional setup after the view.
// The following is not required if configured on the storyboard.
tableView.register (PostCell.self, forCellReuseIdentifier: ListEntry.CellType.post.rawValue)
tableView.register (FolderCell.self, forCellReuseIdentifier: ListEntry.CellType.folder.rawValue)
}
//...
}
register(_:forCellReuseIdentifier:)
calls are not required if you are using the storyboard, but if you are not, be sure to call all cell types
Now, if you really need to separate the processing by cell type, you can separate it based on the value of the cellType
property in ListEntry
.
For example, tableView(_:cellForRowAt:)
should look like this.
functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath)->UITableViewCell{
letlistEntry=mainArray [indexPath.row]
switchlistEntry.cellType{
case.post:
let postcell=tableView.dequeueReusableCell(withIdentifier:listEntry.cellType.rawValue, for:indexPath) as!PostCell
// It seems that you need to use the special properties of `PostCell` instead of `textLabel`
postcell.textLabel?.text=listEntry.text
return postcell
case.folder:
let foldercell=tableView.dequeueReusableCell(withIdentifier:listEntry.cellType.rawValue, for:indexPath) as!FolderCell
// It seems that you should use the 'FolderCell' exclusive property instead of 'textLabel'
foldercell.textLabel?.text=listEntry.text
return foldercell
}
}
(By the way, using as!
, which is considered dangerous, was intentionally intended to "crash me if I set it wrong.")
Now, regarding tableView(_:didSelectRowAt:)
, the "Depending on Type" is written incorrectly, so if you don't rewrite it significantly, you'll have unpredictable problems.
If you want to rewrite it significantly anyway, I will rewrite the part of Post
(ViewController) that accesses List
.With the current code, if there is a design change such as which tab and which VC to display, you will have to rewrite the code.It can't be helped to some extent, but it's a good design to separate the code from the design as much as possible.
At the moment, Post
seems to be only adding elements, so we have the following protocols in place to implement them in the List
class:
(Actually, editing elements is also necessary, but I will not go any further in this answer because it is too far from the subject of using two different cells.)
(Assume to be added to the same file as List
)
protocol ListEntryDelegate:class{
funcaddEntry(_entry:ListEntry, at index:Int)
}
extension List:ListEntryDelegate{
funcaddEntry(_entry:ListEntry, at index:Int){
mainArray.insert (entry, at:index)
tableView.insertRows(at: IndexPath(row:index, section:0), with:.automatic)
}
}
The Post
prerequisite for using the above delivery will look like this:
class Post:UIViewController {
weak vardelegate —ListEntryDelegate?//<- Added
var postString: String=""
@IBOutlet weak var postTextField: UITextField!
override func viewDidLoad(){
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@ IBAction func postBack(_sender:Any){
self.navigationController?popToRootViewController(animated:true)
let postString=postTextField.text???"
// ↓ Invoke the Deligate method without calling the `List` method yourself
let newEntry=ListEntry (cellType: .post, text:postString)
delete?.addEntry(newEntry, at:0)//<- Can I add it to the top anytime?
}
}
Now, if you make a similar change to the Fol
(ViewController) side (the VC class name doesn't need to be written so many times, I think it's better to use a more descriptive name), the tableView(_:didSelectRowAt:)
in the List
class will look like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let listEntry = mainArray[indexPath.row]
switch listEntry.cellType {
case .post:
guard let postVC = storyboard?.instantiateViewController(withIdentifier: "Post") as? Post else {
return
}
postVC.delegate = self
postVC.postString = listEntry.text
/ character/or other and ` Status information set here if there is any information that would deliver a C '
//postVC.〜 = 〜
navigationController?.pushViewController(postVC, animated: true)
case .folder:
guard let folderVC = storyboard?.instantiateViewController(withIdentifier: "Folder") as? Fol else {
return
}
folderVC.delegate=self
// If you have any other information to tell `folderVC`, set it up here
// folderVC.~=~
navigationController?pushViewController (folderVC, animated:true)
}
}
In tableView(_:didSelectRowAt:)
, didSelectRowAt:
is passed to the value of type IndexPath
.Declaring it in the UITableViewCell
type can cause unpredictable failures during execution.
(Actually, the Swift compiler determines, "This is not tableView(_:didSelectRowAt:)
in UITableViewDelegate
!")
There are a lot of changes and it's a little ugly, but please read carefully which part of the class you want to modify and try it out.
As it has become somewhat difficult to read, there will be some things you don't understand or don't understand, but
If you use it differently, I think it would be better if you read this thread later.
List
class summary.I think I confused you because I took advantage of the explanation and cut the code apart. If you apply all of the above modifications to a file (List.swift?) that contains the List
class, it looks like this:
import UIKit
classList:UIViewController, UITableViewDataSource, UITableViewDelegate{
varmainArray: ListEntry = [ ]
// let initArray: [String] = [ ]
override func viewDidLoad(){
super.viewDidLoad()
tableView.dataSource=self
tableView.delegate=self
// Do any additional setup after the view.
// The following is not required if configured on the storyboard.
tableView.register (PostCell.self, forCellReuseIdentifier: ListEntry.CellType.post.rawValue)
tableView.register (FolderCell.self, forCellReuseIdentifier: ListEntry.CellType.folder.rawValue)
}
@IBOutlet weak variableView:UITableView!
functableView(_tableView:UITableView, numberOfRowsInSection section:Int) - > Int{
return mainArray.count
}
functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath) - >UITableViewCell{
let listEntry = mainArray[indexPath.row]
switch listEntry.cellType {
case .post:
let postcell=tableView.dequeueReusableCell(withIdentifier:listEntry.cellType.rawValue, for:indexPath) as!PostCell
// It seems that you need to use the special properties of `PostCell` instead of `textLabel`
postcell.textLabel?.text=listEntry.text
return postcell
case .folder:
let foldercell=tableView.dequeueReusableCell(withIdentifier:listEntry.cellType.rawValue, for:indexPath) as!FolderCell
// It seems that you should use the 'FolderCell' exclusive property instead of 'textLabel'
foldercell.textLabel?.text=listEntry.text
return foldercell
}
}
functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){
let listEntry = mainArray[indexPath.row]
switch listEntry.cellType {
case .post:
guard let postVC = storyboard?.instantiateViewController(withIdentifier: "Post") as? Post else {
return
}
postVC.delegate = self
postVC.postString = listEntry.text
/ character/or other and ` Status information set here if there is any information that would deliver a C '
//postVC.〜 = 〜
navigationController?.pushViewController(postVC, animated: true)
case .folder:
guard let folderVC = storyboard?.instantiateViewController(withIdentifier: "Folder") as? Fol else {
return
}
folderVC.delegate=self
// If you have any other information to tell `folderVC`, set it up here
// folderVC.~=~
navigationController?pushViewController (folderVC, animated:true)
}
}
} //<- where `List` class definition is over
protocolListEntryDelegate:class{
funcaddEntry(_entry:ListEntry, at index:Int)
}
extension List:ListEntryDelegate{
funcaddEntry(_entry:ListEntry, at index:Int){
mainArray.insert (entry, at:index)
tableView.insertRows(at: IndexPath(row:index, section:0), with:.automatic)
}
}
Isn't the place where ListEntryDelegate
and ListEntryDelegate
are listed differently from what I tried? (I'm sorry it's hard to understand.) Please try again with this content.
© 2024 OneMinuteCode. All rights reserved.