TableView.delegate unexpectedly found nil - on a child view controller - ios

I have a tableView, that is accessed via a sideMenu where this particular viewController is a child viewController.
For some reason, when I add the tableView.delegate = self, also tableView.dataSource
and register the cell. My app crashes. When I set this view Controller as the initial view controller the table view shows up, however when I return it to my home page, the app crashes, and does not want to load.
My IBOutlets are connected correctly. I even tried connecting the data source and delegate in storyboard.
I have added two types of code for you all to look at, the first, has an IBOutlet, the second I have tried an addSubView(table) however, no table appears.
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(table)
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
Here is my Wallet View Controller
//
// WalletViewController.swift
// handlwithcare
//
// Created by Charles Morgan on 16/10/2021.
//
import UIKit
import RealmSwift
class WalletViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let button = UIButton()
#IBOutlet var table: UITableView!
private var data = [AddCardItem]()
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
view.backgroundColor = UIColor(named: "RED")
button.setTitle("Add New Card", for: .normal)
view.addSubview(button)
button.backgroundColor = UIColor(named: "yellow-2")
button.setTitleColor(UIColor(named: "RED"), for: .normal)
button.frame = CGRect(x: 50, y: 800, width: 350, height: 50)
button.layer.cornerRadius = 15
button.addTarget(self, action: #selector(didTapAddButton), for: .touchUpInside)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data[indexPath.row].item
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
#objc private func didTapAddButton() {
let rootVC = addCardViewController()
let navVC = UINavigationController(rootViewController: rootVC)
navVC.modalPresentationStyle = .fullScreen
present(navVC, animated: true)
}
}
class AddCardItem: Object {
#objc dynamic var item: String = ""
#objc dynamic var date: Date = Date()
}
Here is my Second attempt with a view.addSubView
import UIKit
import RealmSwift
class WalletViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let button = UIButton()
let table = UITableView()
private var data = [AddCardItem]()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(table)
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
view.backgroundColor = UIColor(named: "RED")
button.setTitle("Add New Card", for: .normal)
view.addSubview(button)
button.backgroundColor = UIColor(named: "yellow-2")
button.setTitleColor(UIColor(named: "RED"), for: .normal)
button.frame = CGRect(x: 50, y: 800, width: 350, height: 50)
button.layer.cornerRadius = 15
button.addTarget(self, action: #selector(didTapAddButton), for: .touchUpInside)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data[indexPath.row].item
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
#objc private func didTapAddButton() {
let rootVC = addCardViewController()
let navVC = UINavigationController(rootViewController: rootVC)
navVC.modalPresentationStyle = .fullScreen
present(navVC, animated: true)
}
}
class AddCardItem: Object {
#objc dynamic var item: String = ""
#objc dynamic var date: Date = Date()
}

Please change the code on the register CELL Tableview.
yourTableView.register(
UINib.init(nibName: "ProductCVC", bundle: nil),
forCellWithReuseIdentifier: "ProductCVC")

Related

unable to dismiss side menu using delegate method in IOS Swift

So, basically, I implemented a SideMenu using the module side menu from pod. however, I am stuck at the last part where when I tapped on any of the options inside the menu, the side menu shall dismiss itself and display corresponding content depending on which menu option I picked.
my code for my main view controller is below:
class Profile: UIViewController, MenuControllerDelegate {
var menu: SideMenuNavigationController?
var menuController:MenuListController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
menu = SideMenuNavigationController(rootViewController: MenuListController())
menu?.leftSide = true
menu?.setNavigationBarHidden(true, animated: false)
SideMenuManager.default.leftMenuNavigationController = menu
SideMenuManager.default.addPanGestureToPresent(toView: self.view)
setupNavBaritem()
}
func handleMenuToggle(menuOption: String?) {
print("menuToggle function reached")
menu?.dismiss(animated: true, completion: nil)
}
func setupNavBaritem() {
let menuicon = UIImage(named: "menu")
let menubtn = UIButton(type: .system)
menubtn.setImage(menuicon, for: .normal)
menubtn.frame = CGRect(x: 0, y: 0, width: 35, height: 35)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: menubtn)
menubtn.addTarget(self, action: #selector(menubtntapped), for: .touchUpInside)
navigationController?.navigationBar.isTranslucent = false
}
#objc func menubtntapped(){
present(menu!,animated:true)
}
}
then this is my menu controller:
class MenuListController:UITableViewController {
var menuitems = ["1","2","3","4"]
var delegate:MenuControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(MenuCell.self, forCellReuseIdentifier: "menucell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuitems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "menucell", for: indexPath) as! MenuCell
let menuetext = menuitems[indexPath.row]
let menuicon = menuimg[indexPath.row]
cell.setmenucell(iconimg: menuicon, text: menuetext)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedMenu = menuitems[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
delegate?.handleMenuToggle(menuOption: selectedMenu)
}
}
and this is my protocol:
protocol MenuControllerDelegate {
func handleMenuToggle(menuOption:String? )
}
New updates!
with the delegate setup, i am able to reach the toggle function and print("menuToggle function reached"). but my dismiss doesnt work. i have been searching for a while and seems a lot of ppl are having trouble using the dismiss function to dismiss this sidemenu. any workaround that may work on this? i tried a few, including setting the new root controller, which didnt work
Change the frame of the centeController on delegate call. Set 0 when you want to dismiss.
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.centerNavigationController.view.frame.origin.x = self.centerNavigationController.view.frame.width - 80
}, completion: nil)
i missed the delegate in this function
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedMenu = menuitems[indexPath.row]
let temp = Profile()
tableView.deselectRow(at: indexPath, animated: true)
self.delegate = temp
delegate?.handleMenuToggle(menuOption: selectedMenu)
}
now, i can print out my menutoggle function!

Elements of the FirstViewController still visible in DetailViewController after using pushViewController method

I first programmatically created a tableview :
private func setupTableView() {
tableView = UITableView(frame: CGRect(x: 0, y: 180, width: view.frame.width, height: view.frame.height), style: UITableView.Style.plain)
tableView.dataSource = self
tableView.delegate = self
tableView.register(ItemTableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
}
and set the cellForRow method as below :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ItemTableViewCell
guard let finalItems = presenter.finalItems?[indexPath.row] else { return cell }
presenter.configure(cell: cell, FinalItem: finalItems)
return cell
}
Then I configure the ItemTableViewCell as below :
class ItemTableViewCell: UITableViewCell {
private var iconImageView : UIImageView = {
let imgView = UIImageView(image: #imageLiteral(resourceName: "Image"))
imgView.contentMode = .scaleAspectFit
imgView.clipsToBounds = true
return imgView
}()
private var titleLabel : UILabel = {
let lbl = UILabel()
lbl.textColor = .black
lbl.font = UIFont.boldSystemFont(ofSize: 12)
lbl.textAlignment = .left
return lbl
}()
func configure(finalItem: FinalItem) {
titleLabel.text = finalItem.title
iconImageView.downloaded(from: finalItem.images_url.small)
}
}
When I push to the DetailViewController with the uinavigationbar, the elements contained in the rows (titles, labels...) are still visible a few milli seconds:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let finalItem = finalItems[indexPath.row]
let detailViewController = ModuleBuilder.createDetailModuleWith(finalItem)
detailViewController.finalItem = finalItem
navigationController?.pushViewController(detailViewController, animated: true)
}
This is not what I am expecting. I never figure this problem out before.

UISearchController cancel button dismisses UITabBarController when tapped multiple times in a row

I use a custom search controller that has a tableView for showing the results,
the problem is when tapping the cancel button multiple times it dismisses the tabBarController.
But if i press it normally it acts as it should be.
class UICustomSearchController: UISearchController {
private var suggestedTableView: UITableView!
weak var suggestionDelegate: SearchSuggestionsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
suggestedTableView = UITableView(frame: CGRect(x: 0, y: searchBar.frame.maxY,
width: view.frame.width,
height: view.frame.height - 70))
suggestedTableView.backgroundColor = UIColor.clear
suggestedTableView.tableFooterView = UIView()
view.subviews.forEach {
if $0.isKind(of: UITableView.self) {
$0.removeFromSuperview()
}
}
view.addSubview(suggestedTableView)
suggestedTableView.dataSource = self
suggestedTableView.delegate = self
suggestedTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
suggestedTableView.addGestureRecognizer(tap)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
suggestedTableView.removeFromSuperview()
suggestedTableView = nil
dismiss(animated: false, completion: nil)
}
func reloadSuggestions() {
suggestedTableView.reloadData()
}
private func dismissView() {
searchBar.text = ""
suggestedTableView.removeFromSuperview()
dismiss(animated: false, completion: nil)
suggestionDelegate?.didDismissed()
}
// MARK: - Actions
#objc func tableTapped(tap:UITapGestureRecognizer) {
suggestedTableView.removeGestureRecognizer(tap)
let location = tap.location(in: suggestedTableView)
let path = suggestedTableView.indexPathForRow(at: location)
if let indexPathForRow = path {
tableView(suggestedTableView, didSelectRowAt: indexPathForRow)
} else {
dismissView()
}
}
}
extension UICustomSearchController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return suggestionDelegate?.suggestions().count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let list = suggestionDelegate?.suggestions() ?? []
cell.textLabel?.text = list[indexPath.row]
cell.textLabel?.textColor = UIColor.color(from: .blueTabBar)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let list = suggestionDelegate?.suggestions() ?? []
searchBar.text = list[indexPath.row]
searchBar.becomeFirstResponder()
suggestionDelegate?.didSelect(suggestion: list[indexPath.row])
}
}
And in the viewController that has search:
func initSearchViews() {
// Create the search controller and specify that it should present its results in this same view
searchController = UICustomSearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.barTintColor = UIColor.white
searchController.searchBar.tintColor = UIColor.color(from: .blueTabBar)
searchController.searchBar.setValue(Strings.cancel.localized, forKey:"_cancelButtonText")
searchController.suggestionDelegate = self
if let searchTextField = searchController!.searchBar.value(forKey: "searchField") as? UITextField {
searchTextField.placeholder = Strings.search.localized
}
// Make this class the delegate and present the search
searchController.searchBar.delegate = self
}
I tried putting this line in viewController but nothing happened:
definesPresentationContext = true

Adding a target to UIButton in UITableViewCell with didSet

I am trying to refactor my code and I can't seem to active the handleFavoriteStar() action from the SearchController when the button is tapped. I was following this video by LBTA on refactoring: https://youtu.be/F3snOdQ5Qyo
Formula Cell:
class FormulasCell: UITableViewCell {
var searchController: SearchController! {
didSet {
buttonStar.addTarget(searchController, action: #selector(searchController.handleFavoritedStar), for: .touchUpInside)
}
}
var buttonStar: UIButton = {
let button = UIButton()
button.setImage( #imageLiteral(resourceName: "GrayStar") , for: .normal)
button.tintColor = UIColor.greyFormula
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
}
Search Controller:
class SearchController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let formulaCell = FormulasCell()
formulaCell.searchController = self
setupTableView()
}
#objc func handleFavoritedStar() {
print("Added to Favorites")
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! FormulasCell
cell.selectionStyle = .none
cell.searchController = self
return cell
}

"self.pushViewController" does not work in Swift4

I would like to make a transition by placing a UITableView within the UINavigationController class and tapping the cell in it.
However, no matter how many times I press cell, it does not make a transition.
The code is the last one, "self.pushViewController (editViewController, animated: true)".
I am assuming navigationPush, but I would like you to tell me why it does not work.
I will ask for answers.
import UIKit
import APIKit
class BookListViewController: UINavigationController {
struct BookInfo {
let bookImage: UIImage?
let bookTitle: UILabel?
let bookPrice: UILabel?
let bookID: UILabel?
}
private lazy var navBar: UINavigationBar = {
let navBar = UINavigationBar()
navBar.frame = CGRect(x: 0, y: view.safeAreaInsets.top, width: view.frame.width, height: 44)
navBar.barTintColor = UIColor.white
let navItem = UINavigationItem()
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(bookAdd))
navItem.rightBarButtonItem = addButton
navItem.title = "書籍一覧"
navBar.pushItem(navItem, animated: false)
return navBar
}()
private lazy var tableView: UITableView = {
let tableView = UITableView()
tableView.frame = CGRect(x: 0, y: navigationBar.frame.size.height + view.safeAreaInsets.top, width: view.frame.size.width, height: view.frame.size.height - view.safeAreaInsets.bottom)
tableView.rowHeight = 100
tableView.delegate = self
tableView.dataSource = self
tableView.register(BookListCell.self, forCellReuseIdentifier: NSStringFromClass(BookListCell.self))
return tableView
}()
private lazy var safeView: UIView = {
let safeView = UIView()
safeView.backgroundColor = UIColor.white
safeView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.safeAreaInsets.top)
return safeView
}()
private lazy var loadButton: UIButton = {
let button = UIButton()
button.setTitle("読込", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 13)
button.backgroundColor = UIColor.blue
button.layer.cornerRadius = 25
button.addTarget(self, action: #selector(moreLoad(sender:)), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
setupUI()
}
}
extension BookListViewController {
private func setupUI() {
view.addSubview(navBar)
view.addSubview(safeView)
view.addSubview(tableView)
view.addSubview(loadButton)
loadButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20.0).isActive = true
loadButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100.0).isActive = true
loadButton.widthAnchor.constraint(equalToConstant: 50.0).isActive = true
loadButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
}
#objc func bookAdd() {
let bookAddViewController = BookAddViewController()
self.present(bookAddViewController, animated: true)
}
#objc func moreLoad(sender: UIButton) {
print("moreLoad!!")
}
}
extension BookListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell: BookListCell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(BookListCell.self), for: indexPath) as? BookListCell {
cell.bookimage.image = UIImage(named: "hoge")
cell.title.text = "書籍一覧"
cell.price.text = "200.000円"
cell.bookDay.text = "2018/12/31"
cell.editButton.setTitle(">", for: .normal)
return cell
}
let cell = UITableViewCell()
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
//個別の情報を載せて遷移
let editViewController = R.storyboard.main.edit()!
self.pushViewController(editViewController, animated: true)
}
}
In storyboard you need to add navigation controller which make this controller as rootviewcontroller. Just by dragging from navigation controller to your tableview controller.
You should extend BookListViewController from UIViewController and present this controller from another controller like this self.present(UINavigationController(rootViewController: BookListViewController()), animated: true) then you can access navigationItem easily with self.navigationItem inside BookListViewController.
self show current context when we use self.navigationController then we are actually telling push to perform that push on that current view's navigation controller
use:
self.navigationController.pushViewController(editViewController, animated: true)

Resources