Unable to segue tableview - swift

I am trying to create a Tableview app and here is my code, I am unable to segue due to an error saying cvc.college = colleges[indexPath.row] saying cannot assign value of type 'string' to 'College!'
What do i do?
import UIKit
class ViewController: UIViewController, UITableViewDelegate ,UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
var colleges = ["Harper","UofI","Florida State University"]
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
var college1 = College(name: "Harper", state: "IL", population: "25,000+")
var college2 = College(name: "UofI", state: "IL", population: "44,000+")
var college3 = College(name: "Florida State University", state: "Fl", population:"40,000+")
var colleges = [college1 , college2, college3]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colleges.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
myCell.textLabel!.text = colleges[indexPath.row]
return myCell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if editingStyle == .delete {
colleges.remove(at: indexPath.row)
tableView.reloadData()
let college = colleges[indexPath.row]
}
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let college = colleges[sourceIndexPath.row ]
colleges.remove(at: sourceIndexPath.row)
colleges.insert(college, at: destinationIndexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
heres my code for CollegeViewController
class CollegeViewController: UIViewController {
var college : College!
#IBAction func onTappedSave(_ sender: UIButton) {
college.name = collegeText.text!
college.state = stateText.text!
college.population = populationText.text!
}
#IBOutlet weak var collegeText: UITextField!
#IBOutlet weak var populationText: UITextField!
#IBOutlet weak var stateText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
collegeText.text = college.name
stateText.text = college.state
populationText.text = String(college.population)
}
}

First of all you need to put moveRowAt and prepareForSegue methods inside the ViewController class because currently you have added it as outside the class.
After that your prepareForSegue like this.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
Whole code would be like this.
import UIKit
class ViewController: UIViewController, UITableViewDelegate ,UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
var colleges = ["Harper","UofI","Florida State University"]
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colleges.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
myCell.textLabel!.text = colleges[indexPath.row]
return myCell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if editingStyle == .delete {
colleges.remove(at: indexPath.row)
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let college = colleges[sourceIndexPath.row ]
colleges.remove(at: sourceIndexPath.row)
colleges.insert(college, at: destinationIndexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
}
Note: There is no code of self.performSegue, so I'm considering that you have created segue from UITableViewCell to CollegeViewController.

Related

Is there any better way to send information to child view?

I have a view controller which has a child view. I want to convey information from the view to the child view. To do so, I did this :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "visualize", sender: self)
invoiceNumber = indexPath.row
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! PreviewViewController
vc.invoiceNumber = invoiceNumber
}
But the problem is that the value of invoiceNumber is not updated on the first iteration but on the second. I tried to see what the problem was and found that "invoiceNumber = indexPath.row" runs after "vc.invoiceNumber = invoiceNumber". Please help ! Thanks
Here is the code of printing :
import UIKit
class ViewController: UIViewController {
var invoiceNumber: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print(invoiceNumber)
}
}
Sorry I have mistaken :
var customerData: [[customerInformation]] = []
var itemsData: [[Item]] = []
var totalData: [TotalInformation] = []
var invoiceNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
}
override func viewDidAppear(_ animated: Bool) {
let tabBar = tabBarController as! baseTabBarController
customerData = tabBar.customerData
itemsData = tabBar.itemsData
totalData = tabBar.totalData
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return customerData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let invoiceCell = tableView.dequeueReusableCell(withIdentifier: "invoice", for: indexPath) as! invoiceTableViewCell
invoiceCell.textLabel?.text = (customerData[indexPath.row][0]).input
invoiceCell.detailTextLabel?.text = "Invoice n°" + String(indexPath.row)
invoiceCell.totalLabel.text = (totalData[indexPath.row]).total
return invoiceCell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let tabBar = tabBarController as! baseTabBarController
tabBar.customerData.remove(at: indexPath.row)
//itemData.remove(at: indexPath.row)
tabBar.totalData.remove(at: indexPath.row)
customerData = tabBar.customerData
itemsData = tabBar.itemsData
totalData = tabBar.totalData
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
invoiceNumber = indexPath.row
print(invoiceNumber, "yes")
performSegue(withIdentifier: "visualize", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! PreviewViewController
vc.invoiceNumber = invoiceNumber
}
}
It is the "vc.invoiceNumber = invoiceNumber" which comes before the "invoiceNumber = indexPath.row" as I tried to change the value of invoiceNumber a variable in the view and print out the value in the child view and if showed its value first (I tested -1).
I added the Preview view controller which receives the invoiceNumber :
import UIKit
import WebKit
class PreviewViewController: UIViewController {
#IBOutlet var webPreview: UIWebView!
var invoiceComposer: InvoiceComposer!
var HTMLContent: String!
var invoiceNumber: Int = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print(invoiceNumber)
createInvoiceAsHTML()
}
func createInvoiceAsHTML() {
invoiceComposer = InvoiceComposer()
if let tabBar = tabBarController as? baseTabBarController {
if let invoiceHTML = invoiceComposer.renderInvoice(invoiceNumber: String(invoiceNumber), invoiceDate: "", recipientInfo: tabBar.customerData[invoiceNumber][0].input, items: tabBar.itemsData[invoiceNumber], totalAmount: tabBar.totalData[invoiceNumber].total) {
webPreview.loadHTMLString(invoiceHTML, baseURL: NSURL(string: invoiceComposer.pathToInvoiceHTMLTemplate!)! as URL)
HTMLContent = invoiceHTML
}
}
else {
print("tabBarController is not of type baseTabBarController or either nil ")
}
}
}
Change the order of execution, like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
invoiceNumber = indexPath.row
performSegue(withIdentifier: "visualize", sender: self)
}
I should have connected the segue from the view controller to the child view and not from the cell to the child view.

UISwitches in UITableViewCell change states together

I have a very strange problem in my Swift project. I use UIswitch in my dynamic cells in my one-section uitable. Whenever I click on the 6th switch, the first one changes its state with it and vice versa. The .valueChanged function only works for the one that is clicked (correct behaviour).
I cannot figure out why the switches change state together.
This is the code for table cells:
import UIKit
class RoutineTableViewCell: UITableViewCell {
#IBOutlet weak var selectionSwitch: UISwitch!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var previewImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and here is the code in my table view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoutineTableReuseIdentifier, for: indexPath) as? RoutineTableViewCell
else{
return RoutineTableViewCell()
}
let exercise = section!.exercises[indexPath.row]
cell.title.text = exercise.title
cell.previewImage.image = UIImage(named: (exercise.gifName + ".gif"))
cell.selectionSwitch.addTarget(self, action: #selector(self.addRemoveExercise(_:)), for: .valueChanged)
return cell
}
#IBAction func addRemoveExercise(_ sender: UISwitch!) {
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
if(sender.isOn){
customizedSection?.exercises[indexPath!.row] = section!.exercises[indexPath!.row]
}
else{
customizedSection?.exercises[indexPath!.row] = ExerciseModel()
}
}
Your tableView:
import UIKit
class TableViewController: UITableViewController,switchValues {
func changed(_ cell: UITableViewCell, _ mySwitch: UISwitch) {
let index = tableView.indexPath(for: cell)
switchStates[(index?.row)!] = mySwitch.isOn
tableView.reloadData()
}
var switchStates : [Bool] = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return switchStates.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.mySwitch.isOn = switchStates[indexPath.row]
cell.delegate = self
return cell
}
Your cell:
import UIKit
protocol switchValues {
func changed(_ cell:UITableViewCell,_ mySwitch:UISwitch)
}
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var mySwitch: UISwitch!
var delegate:switchValues!
#IBAction func valueChanged(_ sender: UISwitch) {
delegate.changed(self, mySwitch)
}
}

How to open data which in tableView in new controller, data from FIrebase

I want to send text to firebase, and then retrieve it to tableView, but some data too long and don't fit in one line, so i want that data can be open in new controller, how to release it?
My code:
class UserVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var ref: DatabaseReference?
var databaseHandle:DatabaseHandle?
var postData = [String]()
var postOneData = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
ref = Database.database().reference()
databaseHandle = ref?.child("Child").observe(.childAdded, with: { (snapshot) in
let post = snapshot.value as? String
if let actualPost = post {
self.postData.append(actualPost)
self.tableView.reloadData()
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "MySell") as UITableViewCell!
cell.textLabel?.text = self.postData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showText", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showText" {
if let destinationVC = segue.destination as? ShowText {
}
}
}
Assuming that you have a text label in you ShowText
private var textForShowText = String() // a private class variable
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.textForShowText = self.postData[indexPath.row]
performSegue(withIdentifier: "showText", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showText" {
if let destinationVC = segue.destination as? ShowText {
destinationVC.textLabel.text = textForShowText
}
}
}
Here I am assuming that your ShowText has a UITextLabel named textLabel. Also make sure that the numberOfLines of the text label is set to 0. You can also use a UITextView if you want !!

Custom delegate method is calling

import UIKit
protocol CustomCellDelegate: class {
func liked(dataDict:NSDictionary,index:NSInteger)
}
class NameImageTextCell: UITableViewCell,UIActionSheetDelegate {
weak var delegateCell: CustomCellDelegate?
#IBAction func btnAction(_ sender: UIButton) {
if delegateCell==nil{
delegateCell?.liked(dataDict: dataNodeDict, index: ItemIndex)
}
}
}
////////
class
FanWallVC:UIViewController,UITableViewDelegate,UITableViewDataSource,
CustomCellDelegate {
#IBOutlet weak var tableView: UITableView!
let objNameImageTextCell = NameImageTextCell()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NameImageTextCell", bundle: nil),
forCellReuseIdentifier: "NameImageTextCell")
objNameImageTextCell.delegateCell=self
}
func liked(dataDict: NSDictionary, index: NSInteger) {
print("Called")
}
}
When i Click on IBAction(btnAction) in NameImageTextCell, delegateCell is nil,
So liked method is not getting call.
Please help me.
Thanks in advance
You probably should call:
objNameImageTextCell.delegateCell = self
in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
so it should look somthing like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NameImageTextCell", for: indexPath) as! NameImageTextCell
cell.delegateCell = self
//other cell customization
return cell
}

Swift MapKit Autocomplete

I am trying to set an address autocomplete in my view controller so users do not have to type the whole address and instead select it from below the search textfield. This is how my controller looks like:
import Foundation
import UIKit
import MapKit
extension AddNewAddressViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
}
}
class AddNewAddressViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
override func viewDidLoad() {
searchCompleter.delegate = self
searchCompleter.queryFragment = addressSearch.text!
searchResultsTableView.dataSource = self
super.viewDidLoad()
}
#IBOutlet weak var addressSearch: UITextField!
#IBOutlet weak var searchResultsTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let searchResultsCount = searchResults.count
return searchResultsCount
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.subtitle
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
#IBAction func defaultAddressButton(_ sender: Any) {
}
#IBAction func addAddressButton(_ sender: Any) {
}
}
I am getting an error that says:
Type AddNewAddressViewController does not conform to protocol 'UITableViewDataSource'
What am I missing?
Thanks in advance.
You left out the underscore for first parameter of the cellForRowAtIndexPath declaration, which is required under swift 3.0:
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
[etc.]
As a result, you don't have a required function matching the expected signature.