I have a navigationController and I have added a custom UIBarButtonItem. What I want to do is when the user tap my button , it present a viewController which has a tableView inside it.
For that ,I have written this :
let shopoingCarVC:shopingCartProductsList = shopingCartProductsList()
self.navigationController?.pushViewController(shopoingCarVC, animated: true)
shopingCartProductsList is my ViewController I intended to navigate to and when It navigate to that It gave me unexpected found nil error at this line :
tableViewProducts.dataSource = self
I have done it before on my other viewControllers but I got this problem when navigating without segue and with using pushViewController mehod.
This is my targetViewCOntroller :
import UIKit
import Alamofire
import Haneke
class shopingCartProductsList: BaseViewController ,UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var ShopingCartProducts: UITableView!
var products = dataService.instance.shopingCartProduct
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
}
override func viewDidLoad() {
super.viewDidLoad()
ShopingCartProducts.dataSource = self
ShopingCartProducts.delegate = self
self.view.backgroundColor = COLOR_BACKGROUND
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let tblCell = tableView.dequeueReusableCellWithIdentifier("shopingCart_cell") as? shopingCart_cell {
if let prod = products[indexPath.row] as? productMD{
tblCell.configCell(prod)
}
return tblCell
}else{
return shopingCart_cell()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("products count \(products.count)")
return products.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
}
What's wrong ?
Use are wrong while pushing viewcontroller user below code.
let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController self.navigationController?.pushViewController(secondViewController, animated: true)
Set identifier in Identity inspector.
Related
In this split view was not displaying on the iPad screen if I drag it was displaying and if I select an index it is not displaying on the label
class ListTableViewController: UITableViewController {
let names = ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath)
cell.isSelected = true
cell.textLabel?.text = names[indexPath.row]
return cell
}
// MARK:- Storyboard segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "ShowDetailIdentifier") {
var detail: DetailsViewController
if let navigationController = segue.destination as? UINavigationController {
detail = navigationController.topViewController as! DetailsViewController
} else {
detail = segue.destination as! DetailsViewController
}
if let path = tableView.indexPathForSelectedRow {
detail.selectedIndex = path.row + 1
}
}
}
the code in master view controller
#IBOutlet weak var numberLabel: UILabel!
var selectedIndex:Int = 1
override func viewDidLoad() {
super.viewDidLoad()
numberLabel?.text = "\(selectedIndex)"
print(selectedIndex)
if splitViewController?.responds(to: #selector(getter: UISplitViewController.displayModeButtonItem)) == true {
navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
navigationItem.leftItemsSupplementBackButton = true
}
the code in details view controller
class SplitViewController: UISplitViewController,UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
splitViewController?.preferredDisplayMode = .primaryOverlay
splitViewController?.delegate = self
// Do any additional setup after loading the view.
}
func splitViewController(_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
return true
}
the code for split view controller
you are missing thisatableView.reloadData()on yourviewDidLoadorviewDidAppear
I can't see where are you initializing the splitviewcontroller you need to pass the TableViewController, and detailViewController.
You need to pass it in the viewDidLoad of the class inheriting form UISplitViewController
self.viewControllers = [masterNav, detail]
and to always show splitviewcontroller you need this
self.displayMode = .allVisible
I am struggling with getting my care data to populate my second tableview controller. The data is populating the first tableview and I can select a row and the segue is used to go to the second table but the labels are not populated.
I've looked all over and have found older samples or obj-c but I cannot figure it out, so any help pointing this n00b in the right direction will be helpful.
Here is what I have, I think I am missing how to populate a variable to pass in prepareForSegue in the list tableview, but I could be wrong. I get a warning error in that function (Warning cannot assign value of type 'ListEntity' to type '[ListEntity]').
CoreData
Entity = ListEntity
Attributes = title, event & location (all as Strings)
listTableViewController
import UIKit
import CoreData
class ListTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var lists = [ListEntity]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "The List"
let addButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: #selector(ListTableViewController.addButtonMethod))
navigationItem.rightBarButtonItem = addButton
}
func addButtonMethod() {
print("Perform action")
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
reloadData()
tableView.reloadData()
}
func reloadData() {
let fetchRequest = NSFetchRequest(entityName: "ListEntity")
do {
if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [ListEntity] {
lists = results
}
} catch {
fatalError("There was an error fetching the list!")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lists.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ListCell") as! ListTableViewCell
let list = lists[indexPath.row]
cell.configurationWithSetup(list)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("DetailsSegue", sender: self)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailsSegue" {
let destinationVC = segue.destinationViewController as! DetailsTableViewController
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
print(indexPath.row) // Print the Row selected to console
// Place the code to pass data here?
// destinationVC.lists = lists[indexPath.row]
// Warning cannot assign value of type 'ListEntity' to type '[ListEntity]'
}
}
}
listTableViewCell
import UIKit
class ListTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
func configurationWithSetup(list: AnyObject) {
titleLabel.text = list.valueForKey("title") as! String?
}
}
detailsTableViewController
import UIKit
import CoreData
class DetailsTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var lists = [ListEntity]()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
let list = lists[indexPath.row]
cell.configurationWithSetup(list)
return cell
}
}
detailsTableViewCell
import UIKit
import CoreData
class DetailsTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var eventLabel: UILabel!
#IBOutlet weak var locationLabel: UILabel!
func configurationWithSetup(list: AnyObject) {
titleLabel.text = list.valueForKey("title") as! String?
eventLabel.text = list.valueForKey("event") as! String?
locationLabel.text = list.valueForKey("location") as! String?
}
}
The warning contains the answer - just change
var lists = [ListEntity]() to
var lists = ListEntity(), or var lists:ListEntity! and when you prepare for segue set that value.
Then you will need to change
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
// as data source is not array you can just you the item you passed
// let list = lists[indexPath.row]
cell.configurationWithSetup(lists)
return cell
}
You should use a static table view if you just want one cell
More info per you current issue
class DetailsTableViewController: UITableViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var theDetailListEntity:ListEntity!
override func viewDidLoad() {
super.viewDidLoad()
print(theDetailListEntity) // check that you passed it across
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DataCell") as! DetailsTableViewCell
cell.configurationWithSetup(theDetailListEntity)
return cell
}
}
Don't forget to add prepare for segue in the listTableViewController otherwise theDetailListEntity won't be set... and then it will crash.
Depending on how you set up your segue, it may differ. But this is what you need
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("showMyDetailView", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showMyDetailView" {
guard let
vc = segue.destinationViewController as? DetailsTableViewController,
ip = sender as? NSIndexPath else { fatalError() }
let item = lists[ip.row]
vc.theDetailListEntity = item
// set the item in the next VC
tableView.deselectRowAtIndexPath(ip, animated: true)
}
}
I am trying to figure out from long time. Can someone tell me why my delegate method is never called. Its a tvOS project but i believe it should work as simple iOS app. On click of button i have a popup table view and on select i am trying to update button label with selected option.
protocol PopupSelectionHandlerProtocol{
func UpdateSelected(data:String)
}
class PopupViewController: UIViewController, UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var myTable: UITableView!
let months = [1,2,3,4,5,6,7,8,9,10,11,12]
let days = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
let yearsRange = [2015,2016,2017,2018,2019,2020]
var popupType:String!
var delegate:PopupSelectionHandlerProtocol?
override func viewDidLoad() {
super.viewDidLoad()
popupType = "months"
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (popupType == "months"){
return 12
}else if (popupType == "days"){
return 31
}else if (popupType == "years")
{
return 6
}
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = String(months[indexPath.row])
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.text)
delegate?.UpdateSelected((tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.text)!)
self.dismissViewControllerAnimated(true, completion: nil)
}
}
And then This -
class VacationPlannerController: UIViewController,PopupSelectionHandlerProtocol {
#IBOutlet weak var fromMonth: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let popupDelegate = PopupViewController()
popupDelegate.delegate = self
}
func UpdateSelected(data:String){
print("Inside UpdateSelected VacationPlannerController \(data)")
fromMonth.titleLabel?.text = data
}
}
The problem is that, you are getting your delegate as nil, since there can be only one ViewController at a time presented. Since your popupViewController's view is not loaded. The viewDidLoad() method is not getting called, resulting in non-setting of popupDelegate.
If you want to check its nullity. Try this in your didSelect... Method
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.navigationController?.pushViewController(VacationPlannerController(), animated: true)
if(delegate==nil){
print("delegate is nil")
}
delegate?.UpdateSelected((tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.text)!)
}
If you want the fromMonth button to be updated. First you will need to present/push VacationPlannerController in order to call its viewDidLoad(). Then only you will be able to update its property, that is, fromMonth label.
Two things to resolve this issue -
First in PopupViewController-
In didSelectRowAtIndexPath, replaced
delegate?.UpdateSelected((tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.text)!)
with
self.delegate?.UpdateSelected((tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.text)!)
And Second in VacationPlannerController-
Removed below code from viewDidLoad -
let popupDelegate = PopupViewController()
popupDelegate.delegate = self
And added prepareForSegue -
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as! PopupViewController
destinationVC.delegate = self
}
And issue resolved yeeee :)
I am using a library called SwiftPages. It works fine. But when i perform a Push Segue from this View Controller to another the navigation bar self.navigationController is nil ?
How can i add the navigation bar into the pushed VC ?
ViewController
class CoursePageController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var ChapterTable: UITableView!
#IBOutlet weak var courseDesc: UITextView!
var CourseName : String!
var ChapName : [String] = []
var ChapId : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = CourseName
self.courseDesc.text = CourseDescriptionC
self.courseDesc.setContentOffset(CGPointZero, animated: true)
HUD()
ChapterTable.estimatedRowHeight = 120
ChapterTable.rowHeight = UITableViewAutomaticDimension
getData()
}
func HUD(){
progress.show(style: MyStyle())
}
func getData(){
Alamofire.request(.GET, "http://www.wve.com/index.php/capp/get_chapter_by_course_id/\(CourseIdinController)")
.responseJSON { (_, _, data, _) in
let json = JSON(data!)
let catCount = json.count
for index in 0...catCount-1 {
let cname = json[index]["CHAPTER_NAME"].string
let cid = json[index]["CHAPTER_ID"].string
self.ChapName.append(cname!)
self.ChapId.append(cid!)
}
self.ChapterTable.reloadData()
self.progress.dismiss()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return ChapName.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : UITableViewCell = self.ChapterTable.dequeueReusableCellWithIdentifier("ChapCell") as! UITableViewCell
cell.textLabel?.text = self.ChapName[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//Here the navigationController is nil
self.navigationController?.pushViewController(self.storyboard!.instantiateViewControllerWithIdentifier("LessonController") as! UIViewController, animated: true)
// performSegueWithIdentifier("ChapSegue", sender: nil)
}
EDIT
I have added the Navigation controller as my Initial VC. The Course page Controller is shown from the SwiftPages.
I can't find how it is being presented. Please take a look at this file.
https://github.com/GabrielAlva/SwiftPages/blob/master/SwiftPages/SwiftPages.swift
Thanks in Advance!
Did you put CoursePageController in NavigationController? If yes then check how it is presented?
If it is presented modally then you won't get the navigationController reference.
This will work if you have navController as rootViewController
if let navController = UIApplication.sharedApplication().keyWindow?.rootViewController as? UINavigationController {
//get the nav controller here and try to push your anotherViewController
}
i have ThirdView in my "start" view
import Foundation
import UIKit
class ThirdView : UITableViewController {
var jsonz:NSArray = ["Ray Wenderlich"];
var valueToPass : String?;
var programVar : String?;
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
var newProgramVar = "lol";
let destinationVC = segue.destinationViewController as! FourthView
destinationVC.programVar = newProgramVar
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.jsonz.count;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
myCell.textLabel?.text = self.jsonz[indexPath.row] as? String;
return myCell;
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let valueToPass = "asd";
let destinationVC = FourthView()
destinationVC.valuePassed = valueToPass;
self.performSegueWithIdentifier("restDetail", sender: tableView);
}
}
I have a segue identifier: restDetail
When i run a project and click on cell, i cant recieve a variable valuePassed in "second" view, i get nil. Please help, why?
But i normal recieve a variable programVar from function prepareForSegue, it is ok. I have only problem with didSelectRowAtIndexPath segue.
It is my FourthView:
import UIKit
class FourthView: UIViewController {
var valuePassed:String!
var programVar:String!
override func viewDidLoad() {
super.viewDidLoad()
println(valuePassed);
println(programVar);
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
See here what i have in output:
nil
lol
nil
lol
And second question: why in output it shows 4 times?
Sorry for my english.
In didSelectRowAtIndexPath you are not initializing the FourthView instance correctly.
This line:
let destinationVC = FourthView()
Creates a random instance of FourthView, that isn't the one you're using as destination.
If you want to pass a value to the FourthView it's usually best to do that in prepareForSegue.
As you can see in the line below, here you are setting the destinationVC variable to FourthView instance, which is the destination View Controller of your segue.
let destinationVC = segue.destinationViewController as! FourthView
The issue is with the following code:
let valueToPass = "asd";
let destinationVC = FourthView()
destinationVC.valuePassed = valueToPass;
You are allocating a temporary instance of FourthView and passing data to it. And after that you perform a segue. Perform segue initialises your view controller and loads it to the view (different one, not the one you initialised manually in the didSelectRowAtIndexPath). You need to pass the data from the prepareForSegue: method.