I added cell to my tableView and i want to show image in any cell i added an array of image to my class "MathViewController" and i want show these images in per cell.but no image show in any of cell.Do any one know about my problem? I'm very new to swift if you help me it will be great.
its my class MathTableViewCell to get the image from story board:
import UIKit
class MathTableViewCell: UITableViewCell{
#IBOutlet weak var imageCell: UIImageView!
}
and here is the class MathViewController:
import UIKit
class MathViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableController: UITableView!
let items = ["Calculatorimg" , "ss"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableController.register(UITableViewCell.self, forCellReuseIdentifier: "MathTableViewCell")
tableController.rowHeight = UITableViewAutomaticDimension
tableController.estimatedRowHeight = 44
tableController.delegate = self
tableController.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MathTableViewCell", for: indexPath) as? MathTableViewCell{
cell.imageCell.image = UIImage(named: items[indexPath.row])
return cell
}
return UITableViewCell()
}
}
and here is my storyboard as you cell identifier has been set to MathTableViewCell:
storyboard
Part 1: If create new Xib for cell.
Whole code is correct but forgot to register UITableViewCell Nib file into tableView.
Add below code in ViewDidLoad
tableController.register(UINib(nibName: "MathTableViewCell", bundle: nil), forCellReuseIdentifier: "MathTableViewCell")
Part 2: Cross Verify CellReuseIdentifier is correct.
Related
I have two custom TableViewCells. So first TableViewCell is like a recent list, it can become longer. but second cell is always stays at bottom. so i need to add UILabel that hold's secondTableViewCell. the result that i need.
import UIKit
class bagPage: UIViewController, UITableViewDelegate, UITableViewDataSource {
var itemsName: [String] = []
var itemsPhoto: [UIImage] = []
// these arrays will defined in other view controller
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row < itemsName.count{
return 165
}else{
return 50
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6 + itemsName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < itemsName.count{
let cell = tableView.dequeueReusableCell(withIdentifier: "bagTableViewCell") as? bagTableViewCell
cell?.itemName.text = itemsName.last
cell?.itemPhoto.image = itemsPhoto.last
return cell!
}
if indexPath.row == itemsName.count {
let cellTwo = tableView.dequeueReusableCell(withIdentifier: "extraBagPageTableView") as? extraBagPageTableView
// here i'm hiding views in first row
cellTwo?.textLabel?.text = "These are products that u can add to your cell"
return cellTwo!
}else{
let cellTwo = tableView.dequeueReusableCell(withIdentifier: "extraBagPageTableView") as? extraBagPageTableView
return cellTwo!
}
}
}
This is another attempt at providing a solution. Is this what you are looking for?
Here is a link to the project
https://drive.google.com/file/d/1XlSF4fGiNzOqQHauiNo7TuFhKUTrFbsJ/view?usp=sharing
Let me know if you need more help
Good evening, so I followed your image and made the code follow your convention of 1 tableview section, 2 difference cells. I tried to use your naming convention. Note I had to swap around the height values, you had them wrong way round.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var itemsName: [String] = ["Helmet", "Gloves", "Bindings", "Goggles", "Kneepads", "Boots", "Snowboard"]
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 + itemsName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < itemsName.count{
let bagTableViewCell = tableView.dequeueReusableCell(withIdentifier: "BagTableViewCell") as? BagTableViewCell
bagTableViewCell?.productsLabel.text = itemsName[indexPath.row]
return bagTableViewCell!
} else {
let extraBagPageTableView = tableView.dequeueReusableCell(withIdentifier: "ExtraBagPageTableView") as? ExtraBagPageTableView
return extraBagPageTableView!
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row < itemsName.count {
return 50
} else {
return 165
}
}
}
And the tableview cells. Please note the second cell has a bad name.
class BagTableViewCell: UITableViewCell {
#IBOutlet weak var additionalProductsLabel: UILabel!
#IBOutlet weak var productsLabel: UILabel!
#IBOutlet weak var productImage: UIImageView!
}
class ExtraBagPageTableView: UITableViewCell {
}
And altogether it looks like this
And the project can be found here. (I set the permissions correctly this time :) )
TableCellWithLabel Project
Overview
I'm trying to better understand how extensions work.
In my app I have a ViewController. There I put a view of another class. In this custom class I put a bunch of buttons and a table view. I want them to display some text inside of my tableView whenever I press them.
The problem is that I want to edit some of the table view functions in order to better adjust it to my ViewController.
What I know
All I know is based on the apple documentation
What I'm doing
What I'm trying to do, I should say, is to add functionality to a custom view's function after adding an object which is of the type of my custom class to the ViewController.
This is my custom class:
class CustomClass: UIView{
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("I want to add stuff here too")
}
//And more stuff that is not useful rn
}
Inside of the ViewController class I have declared a variable of type CustomClass.
#IBOutlet weak var custom: CustomClass!
In my viewDidLoad I call :
custom.setupTable()
What I need to do is creating an extension to edit the tableview that belongs to custom (the variable of type CustomClass that is inside of my ViewController).
I have no clue on how to do that.
I know how to work with extension to expand my code's functionality but I don't know how to use them to edit these other functions.
Question
How do I edit the tableview functions that belong to custom?
Ie. how would I be able to change the number of rows or to change the cell's layout from the class I call the object in?
I hope I was clear enough...
For this specific example...
Add a property to your CustomClass:
class CustomClass: UIView {
// this may be changed by the "calling class"
var numRows: Int = 10
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
In your extension, use that property:
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// don't make this a hard-coded number
//return 10
return numRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
//And more stuff that is not useful rn
}
Then, in your "calling class", you can change that property:
class ExampleViewController: UIViewController {
let myView = CustomClass()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myView)
// constraints, etc
// change the number of rows in the table in myView
myView.numRows = 20
}
}
More likely, though, you would be doing something like setting / changing the data for the table in your custom class.
Here's an example, along with showing how to use a closure to "call back" to the calling class / controller:
class CustomClass: UIView {
// this may be changed by the "calling class"
var theData: [String] = []
// closure to "call back" to the controller
var callback: ((IndexPath) -> ())?
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
cell.textLabel?.text = theData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// tell the controller the cell was selected
callback?(indexPath)
}
}
class ExampleViewController: UIViewController {
let myView = CustomClass()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myView)
// constraints, etc
// set the data in CustomClass
myView.theData = [
"First row",
"Second row",
"Third",
"Fourth",
"etc..."
]
myView.callback = { indexPath in
print("CustomClass myView told me \(indexPath) was selected!")
// do what you want
}
}
}
I would like to show table view with cell where will be one label and tableview below this label. I have such layout right now:
view above my tables view will be hidden in some conditions so as a result I will have table view on whole screen. So... I found this video where developer managed to solve my task. I did everything similarly to his video but I didn't manage to show table view inside table view cell. Here is my steps:
Added all views to general view.
Attached tags to my table views: 100 for main table view and 90 for inside table view.
Created cell classes and attached them to both cells.
Added extension at main cell like in video.
Handled table view tag in main view controller.
As I see the problem is with inside table view which can't be shown. Below you can see classes for cells. Main cell:
class GeneralCell : UITableViewCell {
#IBOutlet weak var answerOptions: UITableView!
#IBOutlet weak var questionText: UILabel!
}
extension GeneralCell{
func setTableViewDataSourceDelegate <D:UITableViewDelegate & UITableViewDataSource> (_ dataSourceDelegate: D, forRow row: Int)
{
answerOptions.delegate = dataSourceDelegate
answerOptions.dataSource = dataSourceDelegate
answerOptions.reloadData()
}
}
inside cell:
class AnswersCell: UITableViewCell {
#IBOutlet weak var answerOption: UILabel!
}
and here is my view controller:
class PollsController: UIViewController, UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var questionTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
questionTableView.delegate = self
questionTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(tableView.tag)
if tableView.tag == 100 {
let cell: GeneralCell = tableView.dequeueReusableCell(withIdentifier: "GeneralCell") as! GeneralCell
cell.answerOptions.reloadData()
return cell
}else{
let cell: AnswersCell = tableView.dequeueReusableCell(withIdentifier: "AnswersCell") as! AnswersCell
return cell
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if tableView.tag == 100 {
return 1
}else{
return 6
}
}
}
Then I did some test for getting to know where the problem is. I added print() into data loader function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(tableView.tag)
if tableView.tag == 100 {
print("1")
let cell: GeneralCell = tableView.dequeueReusableCell(withIdentifier: "GeneralCell") as! GeneralCell
cell.answerOptions.reloadData()
return cell
}else{
print("2")
let cell: AnswersCell = tableView.dequeueReusableCell(withIdentifier: "AnswersCell") as! AnswersCell
return cell
}
}
and in the output I saw only one tag:
100
and as I see inside table view can't be loaded but I can't understand why. Maybe someone of you will find problem or mistake?
I suggest you use only one tableview, here some example
struct Answer {
let answerText: String
}
struct Question {
let questionText: String
let answers: [Answer]
}
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var questions: [Question] = []
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...10 {
let question = Question(questionText: "Question \(i)", answers: [
Answer(answerText: "Answer 1 Question \(i)"),
Answer(answerText: "Answer 2 Question \(i)"),
Answer(answerText: "Answer 3 Question \(i)"),
Answer(answerText: "Answer 4 Question \(i)")
])
questions.append(question)
}
tableView.dataSource = self
tableView.delegate = self
tableView.sectionHeaderHeight = UITableView.automaticDimension;
tableView.estimatedSectionHeaderHeight = 44
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return questions.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questions[section].answers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell", for: indexPath) as! AnswerCell
cell.answerLabel.text = questions[indexPath.section].answers[indexPath.row].answerText
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionCell") as! QuestionCell
cell.questionLabel.text = questions[section].questionText
return cell
}
}
Try this
class GeneralCell : UITableViewCell {
#IBOutlet weak var answerOptions: UITableView!
#IBOutlet weak var questionText: UILabel!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(tableView.tag)
if tableView == questionTableView{
let cell: GeneralCell = tableView.dequeueReusableCell(withIdentifier: "GeneralCell") as! GeneralCell
cell.answerOptions.delegate = self
cell.answerOptions.dataSource = self
cell.answerOptions.reloadData()
return cell
}else{
let cell: AnswersCell = tableView.dequeueReusableCell(withIdentifier: "AnswersCell") as! AnswersCell
return cell
}
}
So I'm making a new custom view controller class programmatically that has a table view in it. I'm trying to assign this table view with a custom cell class that I made.
class AllTasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
let tableview = UITableView()
// Number of Rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return coreTasks.count
}
// Cell Data and Configuration
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let task = coreTasks[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell") as! CustomCell // Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
I'm getting a nil value I think it's because I need to specify which tableView has an identifier "taskCell" in the storyboard. how do I do that?
here is the custom cell Class
class CustomCell: UITableViewCell {
#IBOutlet var taskLabel: UILabel!
#IBOutlet var dateLabel: UILabel!
// #IBOutlet var iconsCell: UIImageView!
func setTask(task: NSManagedObject ){
taskLabel.text = task.value(forKey: "name") as? String // this is giving me nil value
dateLabel.text = task.value(forKey: "date") as? String
}
You have to register your tableViewCell class for this table view to be able to use it. Do it in viewDidLoad or any time before the first data load to the tableView
class AllTasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
let tableview = UITableView()
func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
self.view.addSubView(tableView)
tableView.register(CustomCell.self, forCellReuseIdentifier:"taskCell")
tableView.reloadData()
}
// Number of Rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return coreTasks.count
}
// Cell Data and Configuration
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let task = coreTasks[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell") as! CustomCell
I'm trying to clean up my crowded ViewController by moving the UITableViewDataSource (and Delegate) to a seperate class.
While the DataSource was inside the ViewController (see just below), it worked fine
class ViewController: UIViewController, UITableViewDataSource{
//MARK: Properties
#IBOutlet weak var myTableView: UITableView!
let cellIdentifier = "myTableViewCell"
let myArray = ["Label one", "Label two", "Label three"]
override func viewDidLoad()
{
super.viewDidLoad()
myTableView.dataSource = self
}
override func didReceiveMemoryWarning()
{super.didReceiveMemoryWarning()}
//MARK: TableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{return 1}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{return myArray.count}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! myTableViewCell
cell.myLabel.text = myArray[indexPath.row]
return cell
}
}
With The myTableViewCell class
class myTableViewCell: UITableViewCell{
#IBOutlet weak var myLabel: UILabel!
override func awakeFromNib()
{super.awakeFromNib()}
override func setSelected(selected: Bool, animated: Bool)
{super.setSelected(selected, animated: animated)}
}
And this works fine and populates a basic table with the labels filled from the strings in myArray.
However when I move the DataSource to it's own class, as follows, it doesn't work
ViewController
class ViewController: UIViewController
{
//MARK: Properties
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
myTableView.dataSource = myDataSource()
}
override func didReceiveMemoryWarning()
{super.didReceiveMemoryWarning()}
}
and here's the myDataSource class
class myDataSource: NSObject, UITableViewDataSource
{
let cellIdentifier = "myTableViewCell"
let myArray = ["Label one", "Label two", "Label three"]
//MARK: TableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{return 1}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{return myArray.count}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! myTableViewCell
cell.myLabel.text = myArray[indexPath.row]
return cell
}
}
(The myTableViewCell remains the same)
This setup just outputs an empty table, even though all I did was copy-paste the code from the ViewController to myDataSource. What am I missing? (aside form the delegate. I'll deal with that later, first I need to find what's the problem with the data source).
I'm a bit of a rookie to swift, so I'm having a really rough time understanding where I'm going wrong here. Any help at all would be greatly appreciated. If you could just remember in your answer that I'm just starting out, so try not to throw too many complicated concepts at me without explaining. Thanks
Probably the code in your data source never gets called because your data source doesn't get retained by the table here myTableView.dataSource = myDataSource() so basically gets released right away. To solve this, keep the data source as a property.
Declare the separate class as an extension of the ViewController class
extension ViewController: UITableViewDataSource
{
let cellIdentifier = "myTableViewCell"
let myArray = ["Label one", "Label two", "Label three"]
//MARK: TableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{return 1}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{return myArray.count}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! myTableViewCell
cell.myLabel.text = myArray[indexPath.row]
return cell
}
}
I'm using also always delegate methods in an extension declaration but in the same file as the main class