I'm testing Swift and I created a table list to show JSON data, now I would like to show details for each cell, clicking on it, into a new View Controller.
Testing the App I got the click on the cell but I don't see the new View.
This is the code capturing the click into the ViewController.swift:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
private let tableView: UITableView = {
let table = UITableView(frame: .zero,
style: .grouped)
table.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
return table
}()
private let tableView: UITableView = {
let table = UITableView(frame: .zero,
style: .grouped)
table.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
return table
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
parseJSON()
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
}
....
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
vc.selectedImage = "images/logo_2-mini.png"
print("Click \(indexPath) " + vc.selectedImage!) // I see it!
navigationController?.pushViewController(vc, animated: true) // I don't see it
}
}
}
This is the DetailViewController
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var selectedImage: String?
override func viewDidLoad() {
super.viewDidLoad()
print("Pre")
if let imageToLoad = selectedImage{
imageView.image = UIImage(named: imageToLoad)
print("ok")
}
}
}
I'm too newbie with swift! Can you help me here?
If you want to show the DetailViewController you should change your code to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "Detail") as? DetailViewController else { return }
vc.selectedImage = "images/logo_2-mini.png"
print("Click \(indexPath) " + vc.selectedImage!) // I see it!
self.present(vc, animated: true)
}
This way you don't need to embed your ViewController into a navigation controller.
Also, I've created the storyboard variable since I don't see its declaration in your code.
Related
I am using XLPagerTabStrip for segment
i want to show one tableview data in two segment with sorted, for that i am using below code
SegmentViewController code: if i add child_2.isSorted = false then error
Value of type 'UIViewController' has no member 'isSorted'
import UIKit
import XLPagerTabStrip
class SegmentViewController: ButtonBarPagerTabStripViewController {
#IBOutlet weak var testSeg: ButtonBarView!
override func viewDidLoad() {
super.viewDidLoad()
// change selected bar color
// Sets the background colour of the pager strip and the pager strip item
settings.style.buttonBarBackgroundColor = .white
settings.style.buttonBarItemBackgroundColor = .yellow
// Sets the pager strip item font and font color
settings.style.buttonBarItemFont = UIFont(name: "Helvetica", size: 15.0)!
settings.style.buttonBarItemTitleColor = .gray
changeCurrentIndexProgressive = { [weak self] (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
oldCell?.label.textColor = .gray
newCell?.label.textColor = .blue
}
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.buttonBarView.frame = testSeg.frame
}
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SegTableViewController")
let child_2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SegTableViewController")
child_2.isSorted = false
return [child_1, child_2]
}
}
SegTableViewController code: here in both segments showing only sortedArray i need in first segment sortedArray and second segment namesArray.. how to do that.. could anyone please suggest me
import UIKit
import XLPagerTabStrip
class SegTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, IndicatorInfoProvider {
var sortedArray = [String]()
var isSorted = true
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
if isSorted{
return IndicatorInfo(title: "Sorted")
}else{
return IndicatorInfo(title: "Normal")
}
}
#IBOutlet weak var tableView: UITableView!
var namesArray = ["afsdf","ddsfsdf", "hjhgjh", "trytryr", "nvbmvnb", "yuertyri", "bmvmncb", "jgfhk", "ytuioi", "sdfgsfdsh", "mkhjgijik", "gfuyru"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sortedArray = namesArray.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedDescending }
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSorted {
return sortedArray.count
}
else{
return namesArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
if isSorted{
cell.textLabel?.text = sortedArray[indexPath.row]
}
else{
cell.textLabel?.text = namesArray[indexPath.row]
}
return cell
}
}
You need to cast your view controller like this
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
let child_1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SegTableViewController")
let child_2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SegTableViewController")
(child_2 as? SegTableViewController).isSorted = false
return [child_1, child_2]
}
Also, no need for an array for displaying data. Use only one array namesArray like this
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if isSorted {
namesArray = namesArray.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedDescending }
}
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
I am trying to recreate the Notes app in iOS. I have created an initial View Controller which is just a table view. A user can go to a Detail View Controller to compose a new note with a Title and Body section. When they click Done, I want to manipulate the tableView with note's details.
I am struggling saving the details of what the user entered to use on my initial view controller.
Here's my Notes class which defines the notes data:
class Notes: Codable {
var titleText: String?
var bodyText: String?
}
Here is the Detail View controller where a user can input Note details:
class DetailViewController: UIViewController {
#IBOutlet var noteTitle: UITextField!
#IBOutlet var noteBody: UITextView!
var noteDetails: Notes?
var noteArray = [Notes]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(updateNote))
noteTitle.borderStyle = .none
}
#objc func updateNote() {
noteDetails?.titleText = noteTitle.text
noteDetails?.bodyText = noteBody.text
noteArray.append(noteDetails!) // This is nil
// not sure if this is the right way to send the details over
// let vc = ViewController()
// vc.noteArray.append(noteDetails!)
if let vc = storyboard?.instantiateViewController(identifier: "Main") {
navigationController?.pushViewController(vc, animated: true)
}
}
}
I also have an array on my initial view controller as well. I think I need this one to store note data to display in the tableView (and maybe don't need the one on my Detail View controller?). The tableView is obviously not completely implemented yet.
class ViewController: UITableViewController {
var noteArray = [Notes]()
override func viewDidLoad() {
super.viewDidLoad()
print(noteArray)
self.navigationItem.setHidesBackButton(true, animated: true)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(composeNote))
}
#objc func composeNote() {
if let dvc = storyboard?.instantiateViewController(identifier: "Detail") as? DetailViewController {
navigationController?.pushViewController(dvc, animated: true)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
noteArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
return cell
}
Just using Delegate:
First create delegate protocol with a func to send back note to your viewController
protocol DetailViewControllerDelegate: AnyObject {
func newNoteDidAdded(_ newNote: Note)
}
Next add the delegate variable to DetailViewController, and call func noteDataDidUpdate to send data back to viewController
class DetailViewController: UIViewController {
weak var delegate: DetailViewControllerDelegate?
#objc func updateNote() {
....
delegate?.newNoteDidAdded(newNote)
}
}
finally, set delegate variable to viewController and implement this in ViewController
class ViewController: UIViewController {
....
#objc func composeNote() {
if let dvc = storyboard?.instantiateViewController(identifier: "Detail") as? DetailViewController {
dvc.delegate = self
navigationController?.pushViewController(dvc, animated: true)
}
}
}
extension ViewController: DetailViewControllerDelegate {
func newNoteDidAdded(_ newNote: Note) {
// do some thing with your new note
}
}
I want to inject my data manager into my view controller and test it.
The ViewController:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var alert: AlertViewController?
var coreDataManager: CoreDataManagerProtocol?
init(coreDataManager: CoreDataManagerProtocol) {
self.coreDataManager = coreDataManager
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.coreDataManager = CoreDataManager()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
#IBAction func addItem(_ sender: Any) {
alert = UIStoryboard(name: Constants.alertStoryBoard, bundle: nil).instantiateViewController(withIdentifier: Constants.alerts.mainAlert) as? AlertViewController
alert?.title = "Enter your task"
alert?.presentToWindow()
alert?.delegate = self
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return coreDataManager?.getTasks().count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = coreDataManager?.getTasks()[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = data?.value(forKey: Constants.entityNameAttribute) as? String
return cell
}
}
I want to test this through injecting at mock into the view controller:
class CoreDataManagerMock: CoreDataManagerProtocol {
var storeCordinator: NSPersistentStoreCoordinator!
var managedObjectContext: NSManagedObjectContext!
var managedObjectModel: NSManagedObjectModel!
var store: NSPersistentStore!
func getTasks() -> [NSManagedObject] {
managedObjectModel = NSManagedObjectModel.mergedModel(from: nil)
storeCordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
do {
store = try storeCordinator.addPersistentStore(
ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
} catch {
// catch failure here
}
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = storeCordinator
var localTasks = [NSManagedObject]()
let entityOne = NSEntityDescription.insertNewObject(forEntityName: Constants.entityName, into: managedObjectContext)
entityOne.setValue(false, forKey: Constants.entityCompletedattribute)
entityOne.setValue("Enter your task", forKey: Constants.entityNameAttribute)
localTasks.append(entityOne)
return localTasks
}
func save(task: String) {
//
}
}
But I'm struggling to test this.
I can't request a cell as I'm not instantiating from the Storyboard (and I can't, since I need to inject the mock core manager.
In every test I try to run tableView resolves to nil
Here is my attempt, thinking I can test my cellForRowAt function directly:
func testtv() {
let CDM = CoreDataManagerMock()
let viewController = ViewController(coreDataManager: CDM)
viewController.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))
let actualCell = viewController.tableView?.cellForRow(at: IndexPath(row: 0, section: 0) )
let test = viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))
XCTAssertEqual(actualCell?.textLabel?.text, actualCell?.textLabel?.text)
}
But as tableView is nil is nil so I can't register the cell. How can I test cellForRow(at: when I inject my dependency as above?
How I did testing with UIStoryboard instantiated UIViewControllers was by doing this.
// STEP 1
// instantiate the storyboard
let storyboard = UIStoryboard(name: "SomeStoryboard", bundle: nil)
// STEP 2
// instantiate the UIViewController using the storyboard
let sampleViewController = storyboard.instantiateViewController(withIdentifier: "SampleViewController") as! SampleViewController
// STEP 3
// set the properties you need to set
sampleViewController.xxxxx = "foo"
sampleViewController.yyyyy = "bar"
// STEP 4
// call the view so the ui objects would be instantiated
// not doing this would cause a crash
// this also calls `viewDidLoad()`
_ = sampleViewController.view
So in your case since this is how the code would look like:
func testtv() {
let storyboard = UIStoryboard(name: "INSERT STORYBOARD NAME HERE", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
viewController.coreDataManager = CoreDataManagerMock()
_ = viewController.view
// I'm not sure about the code below this comment
// but the above code should work
viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))
let actualCell = viewController.tableView?.cellForRow(at: IndexPath(row: 0, section: 0) )
let test = viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))
XCTAssertEqual(actualCell?.textLabel?.text, actualCell?.textLabel?.text)
}
ViewController
Why this is, is because calling instantiateViewController(withIdentifier: _) uses init?(coder aDecoder: NSCoder)
You can remove this snippet below because you don't need it and it won't work since the UIViewController you're instantiating is from a storyboard.
init(coreDataManager: CoreDataManagerProtocol) {
self.coreDataManager = coreDataManager
super.init(nibName: nil, bundle: nil)
}
What you could do instead is create a static method to instantiate your UIViewController with the parameters you need. Example:
class SomeViewController: UIViewController {
var someObject: SomeObject!
static func instantiate(someObject: SomeObject) -> SomeViewController {
let storyboard = UIStoryboard(name: "SomeStoryboard", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "SomeViewController")
viewController.someObject = someObject
return viewController
}
}
// usage
let vc = SomeViewController.instantiate(someObject: SomeObject())
// or
let vc: SomeViewController = .instantiate(someObject: SomeObject())
i'm learning Dependency Injection and created an app by MVP.
I could inject presenters for a few VCs in AppDelegate using storyboard.
But now I created CustomTableViewCell with .xib that has UIButton on the cell so that I would like to process the detail of it in the presenter file.
I tried to create UINib(nibName~ in AppDelegate but when the presenter in CustomTableViewCell is called, it is nil.
I heard that an instance of a cell called in 'AppDelegate' is going to be disposed of. However I don't know any ways not to make presenter nil.
AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let mainTabVC = UIStoryboard(name: "MainTab", bundle: nil).instantiateInitialViewController() as! MainTabViewController
let userDefault = UserDefault()
let presenter = MainTabPresenter(view: mainTabVC, udManager: userDefault)
mainTabVC.inject(presenter: presenter, userDefaultManager: userDefault)
let addTabVC = UIStoryboard(name: "AddTab", bundle: nil).instantiateInitialViewController() as! AddTabViewController
let alertHandller = AlertHandller()
let addPresenter = AddTabPresenter(view: addTabVC, mainView: mainTabVC, alertHandller: alertHandller)
addTabVC.inject(presenter: addPresenter)
let settingTabVC = UIStoryboard(name: "SettingTab", bundle: nil).instantiateInitialViewController() as! SettingTabViewController
let settingPresenter = SettingTabPresenter(view: settingTabVC)
settingTabVC.inject(presenter: settingPresenter, alertHandller: alertHandller)
let vcs = [mainTabVC, addTabVC, settingTabVC]
let mainTabBar = UIStoryboard(name: "MainView", bundle: nil).instantiateInitialViewController() as! MainTabBarController
mainTabBar.setViewControllers(vcs, animated: false)
// no probs until here (inject functions work)
// this is disposed??
let listCell = UINib(nibName: "ListCell", bundle: nil).instantiate(withOwner: ListCell.self, options: nil).first as! ListCell
let cellPresenter = ListCellPresenter(view: mainTabVC)
listCell.inject(presenter: cellPresenter)
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = mainTabBar
window?.makeKeyAndVisible()
return true
}
VC that tableViewDataSource is written
class MainTabViewController: UIViewController {
private let shared = Sharing.shared
private var presenter: MainTabPresenterInput!
private var userDefaultManager: UserDefaultManager!
func inject(presenter: MainTabPresenterInput, userDefaultManager: UserDefaultManager) {
self.presenter = presenter
self.userDefaultManager = userDefaultManager
}
override func viewDidLoad() {
super.viewDidLoad()
tableViewSetup()
}
func tableViewSetup(){
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ListCell", bundle: nil), forCellReuseIdentifier: "ListCell")
}
}
extension MainTabViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return shared.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell
if let item = presenter.item(row: indexPath.row) {
cell.configure(item: item)
}
return cell
}
}
customTableViewCell
class ListCell: UITableViewCell {
private let shared = Sharing.shared
private var presenter: ListCellPresenterInput!
func inject(presenter: ListCellPresenterInput) {
self.presenter = presenter
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func favButtonTapped(_ sender: Any) {
let row = self.tag
switch shared.items[row].fav {
case true:
favButton.setImage(UIImage(named: "favIconNon"), for: .normal)
case false:
favButton.setImage(UIImage(named: "favIcon"), for: .normal)
}
presenter.countFavIcon(rowAt: row) // this presenter is nil
}
func configure(item: Item) {
・・・
}
}
cell presenter
protocol AddTabPresenterInput {
func addButtonTapped(item item: Item?)
}
protocol AddTabPresenterOutput: AnyObject {
func clearFields()
func showAlert(alert: UIAlertController)
}
final class AddTabPresenter: AddTabPresenterInput {
private weak var view: AddTabPresenterOutput!
private weak var mainView: MainTabPresenterOutput!
private weak var alertHandller: AlertHandllerProtocol!
let shared = Sharing.shared
init(view: AddTabPresenterOutput, mainView: MainTabPresenterOutput, alertHandller: AlertHandllerProtocol) {
self.view = view
self.mainView = mainView
self.alertHandller = alertHandller
}
func addButtonTapped(item item: Item?) {
print("called")
mainView.updateView()
}
}
How Can I solve the issue that presenter is nil?
Hopefully some of you would help me out.
Thank you.
UITableView uses reusable cells, you can find a lot of info in google, here is one of the articles
https://medium.com/ios-seminar/why-we-use-dequeuereusablecellwithidentifier-ce7fd97cde8e
So creating an instance of UITableViewCell in AppDelegate you're doing nothing, it is immediately dispose
Create presenter
// somewhere in your MainTabViewController
let cellPresenter = ListCellPresenter(view: self)
To inject presenter you should use tableView(_:cellForRowAt:) method
// later in code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell
cell.inject(presenter: cellPresenter)
if let item = presenter.item(row: indexPath.row) {
cell.configure(item: item)
}
return cell
}
I have an empty view with a tab bar pictured below, when i load a routine a table appears containing the contents, however it seems to overlay the tab bar killing off app navigation. Its not sized in the storyboard to overlay it and its constraint locked to not do so, so im unsure why this is happening, pics of the issue and VC's code below:
VC Code:
import Foundation
import UIKit
import CoreData
class RoutineController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - DECLARATIONS
#IBAction func unwindToRoutine(segue: UIStoryboardSegue) {}
#IBOutlet weak var daysRoutineTable: UITableView!
#IBOutlet weak var columnHeaderBanner: UIView!
#IBOutlet weak var todaysRoutineNavBar: UINavigationBar!
#IBOutlet weak var addTOdaysRoutineLabel: UILabel!
let date = Date()
let dateFormatter = DateFormatter()
let segueEditUserExerciseViewController = "editExerciseInRoutineSegue"
//This is the selected routine passed from the previous VC
var selectedroutine : UserRoutine?
// MARK: - VIEWDIDLOAD
override func viewDidLoad() {
super.viewDidLoad()
setupView()
daysRoutineTable.delegate = self
daysRoutineTable.dataSource = self
view.backgroundColor = (UIColor.customBackgroundGraphite())
dateFormatter.dateStyle = .short
dateFormatter.dateFormat = "dd/MM/yyyy"
let dateStr = dateFormatter.string(from: date)
todaysRoutineNavBar.topItem?.title = dateStr + " Routine"
}
// MARK: - VIEWDIDAPPEAR
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
}
// MARK: - TABLE UPDATE COMPONENTS
private func setupView() {
updateView()
}
// MARK: - TABLE SETUP
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = self.selectedroutine?.userexercises?.count
{
print("exercises: \(count)")
return count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? TodaysRoutineTableViewCell else {
fatalError("Unexpected Index Path")
}
cell.backgroundColor = UIColor.customBackgroundGraphite()
cell.textLabel?.textColor = UIColor.white
configure(cell, at: indexPath)
return cell
}
// MARK: - VIEW CONTROLER ELEMENTS VISIBILITY CONTROL
fileprivate func updateView() {
var hasUserExercises = false
if let UserExercise = self.selectedroutine?.userexercises {
hasUserExercises = UserExercise.count > 0
}
addTOdaysRoutineLabel.isHidden = hasUserExercises
columnHeaderBanner.isHidden = !hasUserExercises
daysRoutineTable.isHidden = !hasUserExercises
}
// MARK: - SETTING DATA FOR A TABLE CELL
func configure(_ cell: TodaysRoutineTableViewCell, at indexPath: IndexPath) {
if let userExercise = selectedroutine?.userexercises?.allObjects[indexPath.row]
{
print("\((userExercise as! UserExercise).name)")
cell.todaysExerciseNameLabel.text = (userExercise as! UserExercise).name
cell.todaysExerciseRepsLabel.text = String((userExercise as! UserExercise).reps)
cell.todaysExerciseSetsLabel.text = String((userExercise as! UserExercise).sets)
cell.todaysExerciseWeightLabel.text = String((userExercise as! UserExercise).weight)
}
}
}
requested table constraints
Debug hierarchy
The Segue that sends the user back to the view that looses its tab bar
if segue.identifier == "addToTodaySegue" {
let indexPath = workoutTemplateTable.indexPathForSelectedRow
let selectedRow = indexPath?.row
print("selected row\(selectedRow)")
if let selectedRoutine = self.fetchedResultsController.fetchedObjects?[selectedRow!]
{
if let todaysRoutineController = segue.destination as? RoutineController {
todaysRoutineController.selectedroutine = selectedRoutine
}
}
}
I also feel perhaps the viewDidAppear code may cause the issue, perhaps the super class?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
Updated storyboard image
I suspect you need to embed your viewController in a UINavigationController.
Consider the following setup:
I suspect your setup is like the upper one:
TapBar -> ViewController -show segue-> ViewController
Which results in a hidden tapbar, like in your description:
While the bottom setup:
TapBar -> NavigationCntroller -rootView-> ViewController -show segue-> ViewController
results in:
which is what you want, how I understood.
Update
It's hard to see. The screenshot of your Storyboard is in pretty low resulution, but the segues look wrong. Double check them. A Segue of type show (e.g push) looks like this:
Also clear project and derived data. Segue type changes sometime are ignored until doing so.
Try calling this self.view.bringSubviewToFront(YourTabControl).
The previous suggestion should work. But the content at the bottom part of tableview will not be visible as the tabbar comes over it. So set the bottom constraint of tableview as the height of tabbar.