My ViewController is getting way too big because of all the methods needed for UITableViewDelegate and UITableViewDataSource, so I refactored my code to a different file, but now the data doesn't show up anymore...
Here's my current implementation:
In MyViewController.swift
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
}
}
In MyNewDataSourceClass.swift
class myDataSourceClass: UITableViewDelegate, UITableViewDataSource {
let stuff = [1, 2, 3]
init(tableView: UITableView) {
super.init()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel?.text = "please show up"
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.stuff.count
}
}
Any help would be very appreciated. Thank you!
// you need to reload table after setting delegate and datasource
class SomeView: UIViewController {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myDataSourceClass(tableView: myTableView)
myTableView.reloadData()
}
}
Related
I'm builded view like this:
and constrains:
Here is a code:
Main controller
class SelectTagsViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var selectedTagsTableView: UITableView! //added table view
let allTags: [String] = ["Qwerty", "IT", "Manic", "VR", "WishHook", "Books", "Programing", "Aplication", "Something", "Fly", "Swift", "Earth", "Orbit", "Mars", "Summer", "Monkey", "AR", "Space"]
var selectedTags: [String] = ["Qwerty", "IT", "Manic", "VR"]
override func viewDidLoad() {
super.viewDidLoad()
selectedTagsTableView.tableFooterView = UIView(frame: CGRect.zero)
selectedTagsTableView.backgroundColor = .lightGray
selectedTagsTableView.register(SelectedTagCell.self, forCellReuseIdentifier: "SelectedTagCell")
}
}
Extension for tableview
extension SelectTagsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let lable = selectedTags[indexPath.row]
let cell = selectedTagsTableView.dequeueReusableCell(withIdentifier: "SelectedTagCell") as! SelectedTagCell
cell.tagNameLabel.text = lable
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedTags.count
}
}
And class for cells
class SelectedTagCell: UITableViewCell {
#IBOutlet weak var tagNameLabel: UILabel!
#IBOutlet weak var removeTagButton: UIButton!
#IBAction func removeTagButtonTapped(_ sender: Any) {
}
}
But cells aren't displayed:
All code are in one file, and all classes and identifiers are connected to components.
What did I miss?
On the recommendation of #Adrian, I added delegate and datasource below and all now work.
selectedTagsTableView.delegate = self
selectedTagsTableView.dataSource = self
And fixed problem with nil value, removed code below:
selectedTagsTableView.register(SelectedTagCell.self, forCellReuseIdentifier: "SelectedTagCell")
I wrote a function to add a Cell in a UITableView.
numberOfRowsInSection works but cellForRowAt does not work.
class ShopMenuViewCell: UITableViewCell {
#IBOutlet weak var menuTableView: UITableView!
var menuPrice: MenuPrice!
override func awakeFromNib()
{
super.awakeFromNib()
}
}
extension ShopMenuViewCell
{
func setView()
{
self.menuTableView.delegate = self
self.menuTableView.dataSource = self
self.menuTableView.regCells(cells: ["ShopMenuInformationCell"])
DispatchQueue.main.async
{
self.menuTableView.reloadData()
}
}
}
extension ShopMenuViewCell : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ShopMenuInformationCell", for: indexPath) as? ShopMenuInformationCell,
let menu = self.menuPrice,
let name = menu.name,
let price = menu.amt else { return ShopMenuInformationCell() }
return cell
}
}
In ShpMenuInformationCell.swift
class ShopMenuInformationCell: UITableViewCell
{
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var shopNameLabel: UILabel!
#IBOutlet weak var menuNameLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
}
I saw the answer to add a ViewController, but I do not know what to do because it is not a storyboard. (.xib)
I think it is because I add UITableViewCell in the UITableViewCell class.
Do you know why?
I had a problem for about 5 days and found a solution!
First Reference Site: Joel's Answer cellForRowAtIndexPath: not called
Second reference site: Paolo's answer
Swift: UITableViewCell rowheight
When I add another kind of TableCell, the vertical size of the cell in question is small.
So I increased the size of the Cell's RowHeight (frame.height) before reloading the data and it's fixed!
Currently, cellforrowat runs safely. Your answers were helpful to the results.
Please try below code:
class ShopMenuViewCell: UITableViewCell
{
#IBOutlet weak var menuTableView: UITableView!
var menuPrice: MenuPrice!
override func awakeFromNib()
{
super.awakeFromNib()
}
fun setUpTable() {
self.menuTableView.regCells(cells: ["ShopMenuInformationCell"])
self.menuTableView.delegate = self
self.menuTableView.dataSource = self
self.menuTableView.reloadData()
}
}
and call the function setUpTable() from ShopMenuViewCell as an cell.setUpTable()
Try below code:
Solution 1
class ShopMenuViewCell: UITableViewCell {
#IBOutlet weak var menuTableView: UITableView! {
didSet {
self.menuTableView.regCells(cells: ["ShopMenuInformationCell"])
self.menuTableView.delegate = self
self.menuTableView.dataSource = self
}
}
}
Solution 2: Please check Anand Verma Answer
The problem is that UITableView.dataSource works fine with extensions, but does not work with delegates.
I created new project and added just one UITableView to the storyboard.
Here is the code using extension:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
// tableView.dataSource = Delegate()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController: UITableViewDataSource {
//class Delegate: NSObject, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(1) // called several times
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(2) // called
var cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "UITableViewCell")
}
return cell!
}
}
Using delegate:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// tableView.dataSource = self
tableView.dataSource = Delegate()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
//extension ViewController: UITableViewDataSource {
class Delegate: NSObject, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(1) // called several times
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(2) // doesn't called
var cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "UITableViewCell")
}
return cell!
}
}
Has anyone encountered such a problem?
You need to store your Delegate object in you view controller. The reason for this is that dataSource variable of UITableView is a weak variable (so as to prevent retain cycles) - it means that if it isn't stored somewhere in a strong variable, it will immediately get deallocated.
tableView.dataSource = Delegate()
Here you assign new instance of Delegate to a weak variable and nowhere else. Do something like this
class ViewController: UIViewController {
var delegate = Delegate()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self.delegate
}
The dataSource and delegate are both weak. So your Delegate() object with no strong reference will be released after viewDidLoad().
If you want to use delegate this way, just var delegate: Delegate! in your ViewController. Then in the viewDidLoad() :
self.delegate = Delegate()
tableView.delegate = self.delegate
I'm designing an app for my school and I am trying to make a simple directory using a tableview within a view controller. I began by trying to make objects, but then switched to a more simple array, still without any luck. I do not know if it is a problem with the code or with the storyboard. Here is the code for the viewcontroller:
import UIKit
class DirectoryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var backButton2: UIButton!
#IBOutlet weak var directoryTableView: UITableView!
// #IBOutlet weak var nameLabel: NSLayoutConstraint!
// let searchController = UISearchController(searchResultsController: nil)
// var directoryObjects: NSMutableArray! = NSMutableArray()
var names = ["Teacher 1", "Teacher 2", "Teacher 3"]
override func viewDidLoad() {
super.viewDidLoad()
/*
self.directoryObjects.addObject("Teacher 1")
self.directoryObjects.addObject("Teacher 2")
self.directoryObjects.addObject("Teacher 3")
self.directoryTableView.reloadData()
*/
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// Mark - tableview
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let directoryCell = self.directoryTableView.dequeueReusableCellWithIdentifier("directoryCell", forIndexPath: indexPath) as! DirectoryTableViewCell
// directoryCell.directoryLabel.text = self.directoryObjects.objectAtIndex(indexPath.row) as? String
directoryCell.directoryLabel.text = names[indexPath.row]
return directoryCell
}
#IBAction func backButton2Tapped(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Here is the code for the DirectoryTableViewCell:
import UIKit
class DirectoryTableViewCell: UITableViewCell {
#IBOutlet weak var directoryLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
/*
func directoryTableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
*/
}
You have to set the delegates. The easiest way is in the code.
In viewDidLoad add:
directoryTableView.delegate = self
directoryTableView.dataSource = self
This will allow those tableView functions to get called.
I'd also recommend changing:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 3
}
to:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return names.count
}
I inserted a tableview inside a UIViewController. But my code is not working. When I checked I found that none of the tableview functions are not called.
class CustomViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var authorArticlesTableView: UITableView!
var authorid: Int!
var authorname: String!
var articles: [JSON]? = []
func loadArticles(){
let url = "http:here.com/" + String(authorid) + "/"
println(url)
Alamofire.request(.GET, url).responseJSON { (Request, response, json, error) -> Void in
if (json != nil){
var jsonObj = JSON(json!)
if let data = jsonObj["articles"].arrayValue as [JSON]?{
self.articles = data
self.authorArticlesTableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.loadArticles()
println("viewDidLoad")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println("numberOfRowsInSection")
return self.articles?.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell
cell.articles = self.articles?[indexPath.row]
println("cellForRowAtIndexPath")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("WebSegue", sender: indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Any solution for this?
Thanks,
You have to set your view controller as a table view delegate/datasource:
add to the end of the viewDidLoad:
authorArticlesTableView.delegate = self
authorArticlesTableView.dataSource = self
Set table delegate and dataSource :
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
Sometimes, if you forget to drap and drop UITableViewCell to UITableView. XCode don't understand TableView has Cell.
By default, when you drap and drop UITableView into UIViewController. I see UITableView has Cell. But you need to drap and drop UITableViewCell into UITableView also.
It is work with me.
Makes sense to do it in your
#IBOutlet weak var authorArticlesTableView: UITableView!
so it will become
#IBOutlet weak var authorArticlesTableView: UITableView! {
didSet {
authorArticlesTableView.delegate = self;
authorArticlesTableView.dataSource = self;
}
}