Swift 3 UITableView not updating - ios

I was assigned with converting an older Objective C app to Swift.
I had another project come up but when I came back to it and to my somewhat working Swift 2 version, upon updating to Swift 3 the UITableView does not seem to update.
It is built in Interface Builder (IB). The data source and delegate functions are linked in IB.
I made a sample project where I want to reload a different array on a button press. On a button press the main array is set equal to a different array. then self.tableView.reloadData() is called. The array in debugging has a value of 4 and is not empty so numberOfRowsInSection returns a number greater than 0. The table height and width are what you would expect and are visible. The table just does not refresh. The cells populate the first time the array loads.
I have also tried downloading tutorials where they add a new cell to a table but it does not appear to work either. I have also tried manually assigning the app delegate and datasource in MasterViewController.swift. I also tried wrapping the reloadData() call in DispatchQueue.main.async but that did not seem to help either.
Hopefully I'm just missing something very basic here. Below is my MasterViewController file. Thanks for any help.
Current version of Xcode: 8.2.1
Version of swift: 3.0.2
OSX: Sierra 10.12.2
import UIKit
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var objects = [Any]()
var list1 = ["Eggs", "Milk", "Bread", "Bacon"];
var list2 = ["France", "Italy", "England", "Spain"];
var currentArray = [String]();
var setVar = false;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem
if(currentArray.count <= 0){
currentArray = list2;
}else{
currentArray = list1;
}
//self.tableView.dataSource = self;
// self.tableView.delegate = self;
//self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell");
//self.tableView.reloadData();
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
self.navigationItem.rightBarButtonItem = addButton
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
override func viewWillAppear(_ animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertNewObject(_ sender: Any) {
objects.insert(NSDate(), at: 0)
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.insertRows(at: [indexPath], with: .automatic)
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = objects[indexPath.row] as! NSDate
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentArray.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel!.text = currentArray[indexPath.row];
return cell
}
func refreshUI(){
self.tableView.reloadData();
}
func changeVar(){
if(setVar){
currentArray.removeAll();
self.currentArray = self.list1;
setVar = false;
}else{
currentArray.removeAll();
self.tableView.reloadData();
list2.append("Italy");
self.currentArray = self.list2;
setVar = true;
}
self.refreshUI();
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
}
class DetailViewController: UIViewController {
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var test2: UIButton!
#IBOutlet weak var test1: UIButton!
var mc = MasterViewController();
func configureView() {
// Update the user interface for the detail item.
if let detail = self.detailItem {
if let label = self.detailDescriptionLabel {
label.text = detail.description
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.configureView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var detailItem: NSDate? {
didSet {
// Update the view.
self.configureView()
}
}
#IBAction func button1(){
NSLog("here is the button1");
mc.changeVar();
}
#IBAction func button2(){
NSLog("here is the button2");
mc.changeVar();
}
}

Your tableView is using the data of currentArray in cellForRowAt function.
The only place that you assign to currentArray is in viewDidLoad.
Currently, in the code the add button will cause a new string of the current timestamp to the objects array, As the table is pulling data from currentArray and not objects, it will never change.
I do not see changeVar() function being called anywhere in the code.
Change the target of the add button to call changeVar function and see if that updates the data in the table. If not, you'll have to provide the exact code that your saying is not working, as the current code I wouldn't expect it to change anything.
EDIT:
In your detail view controller you are trying to update a value from the master view controller... But.. It is not the same instance.
var mc = MasterViewController();
^^ This code creates a NEW instance of MasterViewController so calling that code wont change anything on your tableView.
change this line to
weak var mc: MasterViewController?
Then when you create the detailviewcontroller you can do:
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.mc = self
Then your DetailViewController has a reference to the master controller and can call the function as expected.

Related

Swift IOS Issues updating Label in DetailView from MasterView

My first posting on stackoverflow, so sorry if its not right
I am using the Master/Detail View template in XCode. This is a BLT Central app and it gets notified of events happening on the BLE device.
I have a Master view, this is updated using
public func UpdateView() {
tableView.beginUpdates()
tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
tableView.endUpdates()
}
This works fine and the TableView shows the updates live whenever the BLE notifies
However I also want to update the detail view live, incase this is being shown.
I have the label linked in the DetailView via:
#IBOutlet weak var detailDescription: UILabel!
And it updates just fine when the MasterView seques to the DetailView
However if I try to update the Label when the BLE notify arrives the #IBOutlet detailDescription has turned to nil, so the update fails (Label not linked)
func UpdateDetail() {
guard let label = detailDescription else {
return; //Label not linked
}
label.text = "New Data"
}
The UpdateDetail() function is also used in viewDidLoad() and in that case its working fine
Whats really weird is that if I add a timer in the DetailView to just do the update
var timer : Timer? = nil
#objc func fireTimer() {
DispatchQueue.main.async {
self.UpdateDetail()
}
}
It works fine, so its possibly something to do with calling the UpdateDetail() function from outside the Detail class.
I have checked if the detailDescription reference gets reset by adding a didSet to the property, and its only called once when the view is loaded
Guess I could use the timer work around, but I am totally baffled why the detailItem appears as nil sometimes, so would be grateful for a sanity check.
UPDATE Gone back to basics_______
So I have now gone back to the standard Apple Master->Detail view template and added a simple timer which updates the list. The ListView updates fine, however it still does not update the detail view dynamically. outside its own class.
I am using on a 1 second timer after MainView is loaded, the list view updates fine, however the detail does not.
When debugging it steps into configureView() fine, but detailDescriptionLabel is nil after the first viewDidLoad()
Have tried all the suggestions below, however in each case the weak reference to the label is nil after the initial Load
Totally baffled
#objc func doTimer() {
for index in 0..<objects.count {
objects[index]=(objects[index] as! NSDate).addingTimeInterval(1)
}
tableView.beginUpdates()
tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
tableView.endUpdates()
DispatchQueue.main.async {
self.detailViewController?.configureView()
}
}
Full code for MasterViewController.swift here, rest is the same as standard template.
import UIKit
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var objects = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navigationItem.leftBarButtonItem = editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
navigationItem.rightBarButtonItem = addButton
if let split = splitViewController {
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
//Added timer here
_ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(doTimer), userInfo: nil, repeats: true)
}
//Update data in list
#objc func doTimer() {
for index in 0..<objects.count {
objects[index]=(objects[index] as! NSDate).addingTimeInterval(1)
}
tableView.beginUpdates()
tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
tableView.endUpdates()
DispatchQueue.main.async {
self.detailViewController?.configureView()
}
}
override func viewWillAppear(_ animated: Bool) {
clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
super.viewWillAppear(animated)
}
#objc
func insertNewObject(_ sender: Any) {
objects.insert(NSDate(), at: 0)
let indexPath = IndexPath(row: 0, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = objects[indexPath.row] as! NSDate
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
}
My answer is based on the provided Git repository.
In MasterViewController - you are calling self.detailViewController?.configureView() but you never assign the detail controller and because it's nil it fails to call the configureView function. You can do that in prepare(for segue: UIStoryboardSegue, sender: Any?) by setting self.detailViewController = controller
This won't still help you with the update of the label value.
The reason fo that is because in #objc func doTimer() { you are always setting (overriding) a new Date object into your array (what you probably aimed for is to update value for same reference). Because of this, the reference you assigned to detailViewController is different and you never update the detailItem in your timer. Hence calling the configureView won't make any change as the value remained the same.
It's happening because your detailDescription label is weak "weak var detailDescription". and each time you write this code
guard let label = detailDescription else {
return; //Label not linked
}
label.text = "New Data"
you create a new object and assign value to that object. So the original value for detailDescription label object doesn't change. Try using the same detailDescription object everytime when you change its value.

How to reload a view-controller after data has been fetched from a network request?

I have a problem and can't seem to fix it after looking at tutorials online and other SO questions with a similar problem, which leaves me to think I've done something wrong/bad practice related in my code.
I have 2 table view controllers.
The first TableViewController is populated from a database, all this works fine. When I click one of the cells it segues to a second TableViewController which also should be populated from a database (depending on what you select in the first VC).
Currently if I click a cell in TVC1 it goes to TVC2 and it's empty, then it I click back within my navigation controller and select something else, it goes back to TVC2 and shows me my first selection. This indicates that TVC2 is being loaded before the network has returned its data from the database.... so, I tried using tableView.reloadData() in various places like viewDidLoad and viewDidAppear, but i just can't seem to get it to work.
Below is both TVC's. I've stuck with MVC design pattern and haven't included the model and severConnection code for each TVC because I don't want to over complicate the post, however if you'd like to see either I will update.
Thanks in advance for any help.
TableViewController1
class MenuTypeTableViewController: UITableViewController, MenuTypeServerProtocol {
//Properties
var cellItems: NSArray = NSArray()
var selectedItem = String()
override func viewDidLoad() {
super.viewDidLoad()
let menuTypeServer = MenuTypeServer()
menuTypeServer.delegate = self
menuTypeServer.downloadItems()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "cellType"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: MenuTypeModel = cellItems[indexPath.row] as! MenuTypeModel
myCell.textLabel?.text = item.type
return myCell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
selectedItem = (selectedCell?.textLabel?.text)!
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "typeItems" {
let destinationVC = segue.destination as? TypeItemsTableViewController
destinationVC?.selectedItem = self.selectedItem
}
}
}
TableViewController2:
class TypeItemsTableViewController: UITableViewController, TypeItemsServerProtocol {
//Properties
var cellItems: NSArray = NSArray()
var selectedItem: String = String()
let typeItemsServer = TypeItemsServer()
override func viewDidLoad() {
super.viewDidLoad()
typeItemsServer.delegate = self
self.typeItemsServer.foodType = self.selectedItem
self.typeItemsServer.downloadItems()
self.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "cellTypeItem"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: TypeItemsModel = cellItems[indexPath.row] as! TypeItemsModel
myCell.textLabel?.text = item.name!
return myCell
}
}
Try adding this to TypeItemsTableViewController
override func viewDidLoad() {
super.viewDidLoad()
cellItems = NSArray()//make sure you have the empty array at the start
typeItemsServer.delegate = self
self.typeItemsServer.foodType = self.selectedItem
self.typeItemsServer.downloadItems()
self.tableView.reloadData()
}
and
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
typeItemsServer.delegate = nil
}
Add this at the top
var cellItems: NSArray = NSArray() {
didSet {
tableview.reloadData()
}
}
Now you can remove other tableview.reloadData() calls since it will automatically be called once cellItems are set...
I think you have a timing problem. You're reloading right after your async data call. You reload but your data isn't in place at that time. Try using functions with escaping or use "didSet" on your data like:
var dataArray: [type] {
didSet {
tableview.reloadData()
}
}

Swift 4 Split View Controller Detail Replaces Master

I just started building an app and right now I am adding 2 Split View Controllers, in my Main.storyboard it looks like this image
I added the following code to my Master:
import UIKit
class ContactsMaster: UITableViewController {
var ContactsDetailController: ContactsDetail? = nil
var objects = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navigationItem.leftBarButtonItem = editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
navigationItem.rightBarButtonItem = addButton
if let split = splitViewController {
let controllers = split.viewControllers
ContactsDetailController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? ContactsDetail
}
}
override func viewWillAppear(_ animated: Bool) {
clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc
func insertNewObject(_ sender: Any) {
objects.insert(NSDate(), at: 0)
let indexPath = IndexPath(row: 0, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showContactDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = objects[indexPath.row] as! NSDate
let controller = (segue.destination as! UINavigationController).topViewController as! ContactsDetail
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
}
And here is my Detail:
import UIKit
class ContactsDetail: UIViewController {
#IBOutlet weak var detailDescriptionLabel: UILabel!
func configureView() {
// Update the user interface for the detail item.
if let detail = detailItem {
if let label = detailDescriptionLabel {
label.text = detail.description
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
configureView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var detailItem: NSDate? {
didSet {
// Update the view.
configureView()
}
}
}
My problem is when I run my app and goto the Split View Controller and select an item in the Master, it does not goto the Detail, but instead replaces the master.
I have a sample app that is just the Split View Controller and I noticed in the App Delegate file of the sample app there is this code in the application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool method:
let splitViewController = window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
splitViewController.delegate = self
And there is also this method:
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
if topAsDetailController.detailItem == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
return false
}
My problem with this code is that my Split View Controller is not the inital controller and my problem with the splitViewController method, I have 2 split view controllers, I can only specificity 1 of them. How do I get this split view controller without making it the inital controller?
your master class must implement UISplitViewControllerDelegate.
so first thing you need to do :
class ContactsMaster: UITableViewController,UISplitViewControllerDelegate {
and override this function in your master:
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
return true
}
then in viewDidLoad(master class) add following cods:
self.splitViewController!.delegate = self;
self.splitViewController!.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
self.extendedLayoutIncludesOpaqueBars = true
I think you skip many steps for configuring splitviewcontroller, if you want to understand all the way you can read one of many tutorials written for it, like:
http://nshipster.com/uisplitviewcontroller/
Did you by chance forget to set the ContactsDetail class for your Detail VC in your Storyboard?

Segue from tableview to detail doesn't work

I'm building a table view for shops in our town, and I'd like to be able to click on the name of the shop to see some more details. You can find some pictures of the main.storyboard and the files here. I also added a video of the problem with the clicking.
The code of the masterViewController is mentioned below:
import UIKit
class MasterTableViewController: UITableViewController {
// MARK: - Properties
var detailViewController: DetailViewController? = nil
var winkels = [Winkel]()
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
winkels = [
Winkel(category:"Literature", name:"Standaard"),
Winkel(category:"Literature", name:"Acco"),
Winkel(category:"Clothing", name:"H&M"),
Winkel(category:"Clothing", name:"C&A"),
Winkel(category:"Clothing", name:"Patio"),
Winkel(category:"Restaurants", name:"De 46"),
Winkel(category:"Restaurants", name:"Het hoekske"),
Winkel(category:"Supermarkets", name:"Carrefour"),
Winkel(category:"Supermarkets", name:"Colruyt")
]
winkels.sortInPlace({ $0.name < $1.name })
if let splitViewController = splitViewController {
let controllers = splitViewController.viewControllers
detailViewController = (controllers[controllers.count - 1] as! UINavigationController).topViewController as? DetailViewController
}
self.tableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
clearsSelectionOnViewWillAppear = splitViewController!.collapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return winkels.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let winkel = winkels[indexPath.row]
cell.textLabel!.text = winkel.name
cell.detailTextLabel?.text = winkel.category
return cell
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let winkel = winkels[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailWinkel = winkel
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
}
The last part shows the segue to the next navigation controller (named showDetail, and is of kind "show Detail (e.g. replace)".
Below is the code of the detailViewController:
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var WinkelImageView: UIImageView!
var detailWinkel: Winkel? {
didSet {
configureView()
}
}
func configureView() {
if let detailWinkel = detailWinkel {
if let detailDescriptionLabel = detailDescriptionLabel, WinkelImageView = WinkelImageView {
detailDescriptionLabel.text = detailWinkel.name
WinkelImageView.image = UIImage(named: detailWinkel.name)
title = detailWinkel.category
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I'm not sure what i'm doing wrong so that the clicking won't work.. Thanks in advance for teaching me how to fix this!
You need to implement the method didSelectRowAtIndexPath for the tableview in the first class. In this, you will perform the segue that actually moves from one ViewController to another.

Swift: Pass UITableViewCell label to new ViewController ** CRASHING **

Have a UITableViewCell that passes data to a ViewController. Now it's crashing and I'm not sure why. Was working before then I started getting fata errors every time I tap one of the cells.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var signin: UITextField!
#IBOutlet weak var password: UITextField!
private let datetimes = ["02/25/16 5:47 PM", "02/25/16 2:47 PM", "02/21/16 5:33 AM"]
private let user = ["StevieE11", "Sikes911", "MaggieMae"]
private let feedback = ["The food was fucking terrible!", "Best food this side of the mason dixon line!", "If that waiter looks at me again I'm going to bite the shit out of him"]
var sendSelectedData = NSString()
override func viewWillAppear(animated: Bool) {
navigationItem.title = "Inbox"
//navigationController!.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont(name: "Helvetica Neue", size: 24)!]
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder()
return true
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return user.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Create a new cell with the reuse identifier of our prototype cell
// as our custom table cell class
let cell = tableView.dequeueReusableCellWithIdentifier("myProtoCell") as! MyTableView
// Set the first row text label to the firstRowLabel data in our current array item
cell.user.text = user[indexPath.row]
// Set the second row text label to the secondRowLabel data in our current array item
cell.feedback.text = feedback[indexPath.row]
//cell.feedback.lineBreakMode = NSLineBreakMode.ByWordWrapping
//cell.feedback.numberOfLines = 2
// Set the datetime label to the datetime array
cell.dateTime.text = datetimes[indexPath.row]
// Return our new cell for display
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//println("You selected cell #\(indexPath.row)!")
// Get Cell Label text here and storing it to the variable
let indexPathVal: NSIndexPath = tableView.indexPathForSelectedRow!
//println("\(indexPathVal)")
let currentCell = tableView.cellForRowAtIndexPath(indexPathVal) as! MyTableView!;
//println("\(currentCell)")
//println("\(currentCell.iOSCellLbl?.text!)")
//Storing the data to a string from the selected cell
currentCell.user.text! = user[indexPath.row]
sendSelectedData = currentCell.user.text!
print(sendSelectedData)
//Now here I am performing the segue action after cell selection to the other view controller by using the segue Identifier Name
self.performSegueWithIdentifier("ShowFeedbackSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Here i am checking the Segue and Saving the data to an array on the next view Controller also sending it to the next view COntroller
if segue.identifier == "ShowFeedbackSegue"{
//Creating an object of the second View controller
let controller = segue.destinationViewController as! FeedbackViewController
//Sending the data here
controller.SecondArray = sendSelectedData as String!
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Any thoughts?
Thanks
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier{
case "ShowFeedbackSegue":
if let controller = segue.destinationViewcontroller as? FeedbackViewController {
controller.SecondArray = sendSelectedData as String! // SecondArray must be of //type string
}
default: break
}
}
}

Resources