Showing optional value as 'nil' while changing the viewController from UITableView - ios

I'm trying to display details from a table row onto another viewController, there are three entities which I want to display on the second VC. Two UILabel and one UIImageView. While in the first VC I'm able to view, when in the second VC, it says 'Optional("")', And don't know how to unwrap it.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate,UITableViewDataSource, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var nameForUser: UITextField!
#IBOutlet var loginButton: UIButton!
#IBOutlet var tableView: UITableView!
let allEvents = Events.allEvents
var nextScreenRow: Events!
override func viewDidLoad() {
super.viewDidLoad()
//nameForUser.text! = "Please Enter Name Here"
// Do any additional setup after loading the view, typically from a nib.
//let userName = nameForUser.text
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.text = ""
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allEvents.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventsCell")!
let event = self.allEvents[indexPath.row]
//print(" row \(indexPath.row)")
cell.textLabel?.text = event.eventName
cell.imageView?.image = UIImage(named: event.imageName)
cell.detailTextLabel?.text = event.entryType
//cell.textLabel?.text = allEvents[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
nextScreenRow = allEvents[indexPath.row]
let view : DetailedEventViewController = self.storyboard?.instantiateViewControllerWithIdentifier("trytry") as! DetailedEventViewController
self.navigationController?.pushViewController(view, animated: true)
print("Selected section \(indexPath.section), row \(indexPath.row)")
print(nextScreenRow.eventName)
view.eventDetails = nextScreenRow.eventName
print(view.eventDetails)
view.typeOfEvent = nextScreenRow.entryType
view.myImage = UIImage(named: nextScreenRow.imageName)
//even the 'print' is used, it is displaying here, but not in the next VC
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.allEvents.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let sec = collectionView.dequeueReusableCellWithReuseIdentifier("eventsSec", forIndexPath: indexPath) as! GridCollectionViewCell
let event = self.allEvents[indexPath.row]
sec.imageView.image = UIImage(named: event.imageName)
sec.caption.text = event.entryType
return sec
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("tryToConnect2", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "successfulLogin"){
segue.destinationViewController as! TabController
//let userName = nameForUser.text
//controller.userName = userName
}
}
#IBAction func loginButtonWhenPressed(sender: UIButton) {
let userName = nameForUser.text
if userName == "" {
let nextController = UIAlertController()
nextController.title = "Error!"
nextController.message = "Please enter a name"
let okAction = UIAlertAction(title: "okay", style: UIAlertActionStyle.Default) {
action in self.dismissViewControllerAnimated(true, completion: nil)
}
nextController.addAction(okAction)
self.presentViewController(nextController, animated: true, completion: nil)
}
}
}
And here is my second VC:
import UIKit
class DetailedEventViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var deatiledEvent: UILabel!
#IBOutlet weak var eventType: UILabel!
var eventDetails = ""
var typeOfEvent = ""
var myImage: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func viewTheElemnts(sender: AnyObject) {
deatiledEvent.text = eventDetails
print(deatiledEvent.text)
eventType.text = typeOfEvent
imageView.image = myImage
}
}
Help would be appreciated greatly. Thank you.

You are creating an instance of DetailedEventViewController in the didSelectRowAtIndexPath and setting the value there. But actually you are moving to DetailedEventViewController using segue. So you should add those values in the prepareForSegue: method.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "trytry")
{
let selectedIndex = self.tableView.indexPathForCell(sender as! UITableViewCell)
nextScreenRow = allEvents[selectedIndex.row]
let view = segue.destinationViewController as! DetailedEventViewController
view.eventDetails = nextScreenRow.eventName
view.typeOfEvent = nextScreenRow.entryType
view.myImage = UIImage(named: nextScreenRow.imageName)
}
}

Unwrap your eventName like this :
view.eventDetails = nextScreenRow.eventName! as String
print(view.eventDetails) view.typeOfEvent = nextScreenRow.entryType
view.myImage = UIImage(named: nextScreenRow.imageName)
self.navigationController?.pushViewController(view, animated: true

Related

How to segue back to filled-in version of TableViewController (Swift)?

I am building a room-booking app for iOS in Xcode 9.3.
Here is the basic layout:
First TableViewController(TVC1): starts empty. Pressing '+' pops up the
Second TableViewController(TVC2) with many fields to fill in.
Once the 'Done' button on TVC2 is pressed I get back to TVC1 which now has a cell (Subtitle style) containing the details inserted.
I would now like to tap on said cell and get back to TVC2 to either check or modify the data.
I have created the segue but upon tapping I get the same version of TVC2 that I get when pressing '+', not the filled in one.
What am I doing wrong?
This is the code relative to TVC1 that I need to edit:
import UIKit
class RegistrationTableViewController: UITableViewController {
var registrations: [Registration] = []
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 registrations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RegistrationCell", for: indexPath)
let registration = registrations[indexPath.row]
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
cell.textLabel?.text = registration.firstName + " " + registration.lastName
cell.detailTextLabel?.text = dateFormatter.string(from: registration.checkInDate) + " - " + registration.roomType.name
return cell
}
#IBAction func unwindFromAddRegistration(unwindSegue: UIStoryboardSegue) {
guard let addRegistrationTableViewController = unwindSegue.source as? AddRegistrationTableViewController,
let registration = addRegistrationTableViewController.registration else { return }
registrations.append(registration)
tableView.reloadData()
}
// MARK: Challenge.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ViewReservationDetails" {
}
}
And here is the code for (TVC2) so that you have more or less all the app available.
import UIKit
class AddRegistrationTableViewController: UITableViewController, SelectRoomTypeTableViewControllerDelegate {
// MARK: Properties
let checkInDatePickerCellIndexPath = IndexPath(row: 1, section: 1)
let checkOutDatePickerCellIndexPath = IndexPath(row: 3, section: 1)
var isCheckInDatePickerShown: Bool = false {
didSet {
checkInDatePicker.isHidden = !isCheckInDatePickerShown
}
}
var isCheckOutDatePickerShown: Bool = false {
didSet {
checkOutDatePicker.isHidden = !isCheckOutDatePickerShown
}
}
var roomType: RoomType?
var registration: Registration? {
guard let roomType = roomType else { return nil }
let firstName = firstNameTextField.text ?? ""
let lastName = lastNameTextField.text ?? ""
let email = emailTextField.text ?? ""
let checkInDate = checkInDatePicker.date
let checkOutDate = checkOutDatePicker.date
let numberOfAdults = Int(numberOfAdultsStepper.value)
let numberOfChildren = Int(numberOfChildrenStepper.value)
let hasWifi = wifiSwitch.isOn
return Registration(firstName: firstName, lastName: lastName, emailAddress: email, checkInDate: checkInDate, checkOutDate: checkOutDate, numberOfAdults: numberOfAdults, numberOfChildren: numberOfChildren, roomType: roomType, wifi: hasWifi)
}
var selectedItem: Registration?
// MARK: Outlets
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var checkInDateLabel: UILabel!
#IBOutlet weak var checkInDatePicker: UIDatePicker!
#IBOutlet weak var checkOutDateLabel: UILabel!
#IBOutlet weak var checkOutDatePicker: UIDatePicker!
#IBOutlet weak var numberOfAdultsLabel: UILabel!
#IBOutlet weak var numberOfAdultsStepper: UIStepper!
#IBOutlet weak var numberOfChildrenLabel: UILabel!
#IBOutlet weak var numberOfChildrenStepper: UIStepper!
#IBOutlet weak var roomTypeLabel: UILabel!
#IBOutlet weak var wifiSwitch: UISwitch!
// MARK: Actions
#IBAction func datePickerValueChanged(_ sender: UIDatePicker) {
updateDateViews()
}
#IBAction func stepperValueChanged(_ sender: UIStepper) {
updateNumberOfGuests()
}
#IBAction func wifiSwitchChanged(_ sender: UISwitch) {
// implemented later
}
#IBAction func cancelButtonTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
// MARK: Methods
func updateDateViews() {
checkOutDatePicker.minimumDate = checkInDatePicker.date.addingTimeInterval(86400)
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
checkInDateLabel.text = dateFormatter.string(from: checkInDatePicker.date)
checkOutDateLabel.text = dateFormatter.string(from: checkOutDatePicker.date)
}
func updateNumberOfGuests() {
numberOfAdultsLabel.text = "\(Int(numberOfAdultsStepper.value))"
numberOfChildrenLabel.text = "\(Int(numberOfChildrenStepper.value))"
}
func updateRoomType() {
if let roomType = roomType {
roomTypeLabel.text = roomType.name
} else {
roomTypeLabel.text = "Not Set"
}
}
func didSelect(roomType: RoomType) {
self.roomType = roomType
updateRoomType()
}
override func viewDidLoad() {
super.viewDidLoad()
let midnightToday = Calendar.current.startOfDay(for: Date())
checkInDatePicker.minimumDate = midnightToday
checkInDatePicker.date = midnightToday
updateDateViews()
updateNumberOfGuests()
updateRoomType()
}
// MARK: TableView Data
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch (indexPath.section, indexPath.row) {
case (checkInDatePickerCellIndexPath.section, checkInDatePickerCellIndexPath.row):
if isCheckInDatePickerShown {
return 216.0
} else {
return 0.0
}
case (checkOutDatePickerCellIndexPath.section, checkOutDatePickerCellIndexPath.row):
if isCheckOutDatePickerShown {
return 216.0
} else {
return 0.0
}
default:
return 44.0
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch (indexPath.section, indexPath.row) {
case (checkInDatePickerCellIndexPath.section, checkInDatePickerCellIndexPath.row - 1):
if isCheckInDatePickerShown {
isCheckInDatePickerShown = false
} else if isCheckOutDatePickerShown {
isCheckOutDatePickerShown = false
isCheckInDatePickerShown = true
} else {
isCheckInDatePickerShown = true
}
tableView.beginUpdates()
tableView.endUpdates()
case (checkOutDatePickerCellIndexPath.section, checkOutDatePickerCellIndexPath.row - 1):
if isCheckOutDatePickerShown {
isCheckOutDatePickerShown = false
} else if isCheckInDatePickerShown {
isCheckInDatePickerShown = false
isCheckOutDatePickerShown = true
} else {
isCheckOutDatePickerShown = true
}
tableView.beginUpdates()
tableView.endUpdates()
default:
break
}
}
// MARK: Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SelectRoomType" {
let destinationViewController = segue.destination as? SelectRoomTypeTableViewController
destinationViewController?.delegate = self
destinationViewController?.roomType = roomType
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
The challenge to this tutorial says to start from here and:
"Update the RegistrationTableViewController(TVC1) with a segue that allows the user to select and view the details of a registration in the AddRegistrationTableViewController(TVC2).
Hope this helps to provide the right solution.
Create a property let say selectedItem in TVC2 screen.
var selectedItem: Registration?
Modify prepare for cell ...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ViewReservationDetails" {
let sourceCell = sender as! UITableViewCell
if let indexPath = tableView.indexPath(for: sourceCell) {
if let dest = segue.destination as? <#Destination view controller#> {
dest.selectedItem = registrations[indexPath.row]
}
}
}
}
And finally in your destination view controller (having TVC2) you need to check selectedItem and assign value in viewDidLoad: or wherever.
override func viewDidLoad() {
super.viewDidLoad()
if let item = selectedItem {
//here set value as you want to views
}
}
Use this code in tableView(_:didSelectRowAt:):
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "ViewReservationDetails", sender: indexPath)
}
Then, in TVC1’s prepare(for:sender:) you pass the selected registrations element plus a completion handler to TVC2, like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ViewReservationDetails" {
if let destination = segue.destination as? AddRegistrationTableViewController, let indexPath = sender as? IndexPath {
destination.registration = registrations[indexPath.row]
destination.completionHandler = { (registration) in
self.registrations.append(registration)
self.tableView.reloadData()
}
}
}
}
In TVC2, you declare a property completionHandler like this:
var completionHandler: ((Registration) -> Void)?
and you call this handler in viewWillDisappear:
completionHandler?(newRegistration)
with newRegistration being the newly created element to be added to the Registration array. This way, you won’t need an unwind segue.

Parse from TableVC to textView in other viewController swift

I am new in programming, and have problem. I am using parse for my array in tableview. When the row is selected i want to segue on another view controller to textView. The tableview works good but i can't get text to textView.
tableVC:
import UIKit
import Parse
class ThirdTableVC: UITableViewController {
#IBOutlet weak var refresherQuotes: UIRefreshControl!
#IBOutlet var quoteTable: UITableView!
var selectedQuote: PFObject?
var quoteItems = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func updateQuotesResults(_ sender: UIRefreshControl) {
fetchQuotesData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadQuoteTexts(selectedQuote: selectedQuote)
}
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 quoteItems.count
}
func fetchQuotesData() {
let quotesQuery = PFQuery(className: "TotalTest")
quotesQuery.whereKey("Subcategory", equalTo: selectedQuote ?? nil)
quotesQuery.findObjectsInBackground { (objects, error) in
if let realCategoryObjects = objects {
self.quoteItems = realCategoryObjects
self.tableView.reloadData()
self.refresherQuotes.endRefreshing()
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let quoteCell = tableView.dequeueReusableCell(withIdentifier: "quoteCell", for: indexPath)
let quoteItem = quoteItems[indexPath.row]
let quoteUserTitle = quoteItem.object(forKey: "TextQuote") as? String
quoteCell.textLabel?.text = quoteUserTitle
return quoteCell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQuoteDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let quoteobject = quoteItems[indexPath.row] as? NSDate
let quoteController = (segue.destination as! UINavigationController).topViewController as! DetailViewController
quoteController.detailItem = quoteobject
quoteController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
quoteController.navigationItem.leftItemsSupplementBackButton = true
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row tapped: \(indexPath.row)")
let selectedQuotes: PFObject = quoteItems[indexPath.row]
let FourthVC = self.storyboard?.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
FourthVC.fourthTextView.text = quoteItems[indexPath.row] as? String
self.navigationController?.pushViewController(FourthVC, animated: true)
}
func loadQuoteTexts(selectedQuote: PFObject!) {
let quoteQuery = PFQuery(className: "TotalQuote")
quoteQuery.whereKey("QuoteSubs", equalTo: selectedQuote ?? nil)
quoteQuery.includeKey("QuoteSubs")
quoteQuery.findObjectsInBackground { (result: [PFObject]?, error) in
if let searchQuoteResults = result {
self.quoteItems = searchQuoteResults
self.quoteTable.reloadData()
}
}
}
}
How can I change this?
viewController with textView:
import UIKit
import Parse
class FourthViewController: UIViewController {
var getQuote: PFObject?
#IBOutlet weak var fourthTextView: UITextView!
#IBOutlet weak var fourthLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
fourthLabel.text! = getQuote as! String
fourthTextView.text! = getQuote as! String
}
}
Please help me to passing texts
If you use pushViewController do it like that , in did selectRowAt
let MainStory: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = MainStory.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
and now pass your text
desVC.getText = "here goes your text u want to pass"
FourthViewController
set up your var
var getText = String()
so you can finally use
self.navigationController?.pushViewController(desVC, animated: true)
so it will pass all parameters you previous add with desVC.getSomething
in FourthViewController you just need to use getText.
The problem is that you are changing from a view to another with pushViewController, by doing that your prepareForSegue won't be executed.
On your didSelectRow you need to call performSegue(withIdentifier:sender:).
You can lookup this question for more information on how to do it.

Not able to display values in another viewcontroller from TableView in Swift

I want to display the details of one one table row onto another viewController. But it shows an error saying ' fatal error: unexpectedly found nil while unwrapping an Optional value'
The code for my VC is as follows:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate,UITableViewDataSource, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var nameForUser: UITextField!
#IBOutlet var loginButton: UIButton!
#IBOutlet var tableView: UITableView!
let allEvents = Events.allEvents
var nextScreenRow: Events!
override func viewDidLoad() {
super.viewDidLoad()
//nameForUser.text! = "Please Enter Name Here"
// Do any additional setup after loading the view, typically from a nib.
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.text = ""
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allEvents.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventsCell")!
let event = self.allEvents[indexPath.row]
cell.textLabel?.text = event.eventName
cell.imageView?.image = UIImage(named: event.imageName)
cell.detailTextLabel?.text = event.entryType
//cell.textLabel?.text = allEvents[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
nextScreenRow = allEvents[indexPath.row]
performSegueWithIdentifier("tryToConnect", sender:self)
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.allEvents.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let sec = collectionView.dequeueReusableCellWithReuseIdentifier("eventsSec", forIndexPath: indexPath) as! GridCollectionViewCell
let event = self.allEvents[indexPath.row]
sec.imageView.image = UIImage(named: event.imageName)
sec.caption.text = event.entryType
return sec
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("tryToConnect2", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "successfulLogin"){
segue.destinationViewController as! TabController
//let userName = nameForUser.text
//controller.userName = userName
}
else if (segue.identifier == "tryToConnect"){
let dest = segue.destinationViewController as! DetailedEventViewController
dest.deatiledEvent.text = nextScreenRow.eventName
dest.eventType.text = nextScreenRow.entryType
dest.imageView.image = UIImage(named: nextScreenRow.imageName)
}
}
#IBAction func loginButtonWhenPressed(sender: UIButton) {
let userName = nameForUser.text
if userName == "" {
let nextController = UIAlertController()
nextController.title = "Error!"
nextController.message = "Please enter a name"
let okAction = UIAlertAction(title: "okay", style: UIAlertActionStyle.Default) {
action in self.dismissViewControllerAnimated(true, completion: nil)
}
nextController.addAction(okAction)
self.presentViewController(nextController, animated: true, completion: nil)
}
}
}
When I run this, it shows the error. I have also assigned the delegates for the table view. The code for 'DetailedEventVC' is:
import UIKit
class DetailedEventViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var deatiledEvent: UILabel!
#IBOutlet weak var eventType: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Why does it show that the values are nil?
Help would be greatly appreciated.
Thanks in advance.
The 'EventsDetails.swift' file which has the details of events are a structure. Is there anything wrong in the way I'm calling the values?
import Foundation
import UIKit
struct Events {
let eventName: String
let entryType: String
let imageName: String
static let EventKey = "NameKey"
static let EntryTypeKey = "EntryType"
static let ImageNameKey = "ImageNameKey"
init(dictionary:[String : String]) {
self.eventName = dictionary[Events.EventKey]!
self.entryType = dictionary[Events.EntryTypeKey]!
self.imageName = dictionary[Events.ImageNameKey]!
}
}
extension Events {
static var allEvents: [Events] {
var eventsArray = [Events]()
for d in Events.localEventsData(){
eventsArray.append(Events(dictionary: d))
}
return eventsArray
}
static func localEventsData()-> [[String: String]] {
return [
[Events.EventKey:"Metallica Concert in Palace Grounds", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"Metallica"],
[Events.EventKey:"Saree Exhibition in Malleswaram Grounds", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"SareeExhibition"],
[Events.EventKey:"Wine tasting event in Links Brewery", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"WineTasting"],
[Events.EventKey:"Startups Meet in Kanteerava Stadium", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"StartupMeet"],
[Events.EventKey:"Summer Noon Party in Kumara Park", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"SummerNoonParty"],
[Events.EventKey:"Rock and Roll nights in Sarjapur Road", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"RockNRollNight"],
[Events.EventKey:"Barbecue Fridays in Whitefield", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"BBQFriday"],
[Events.EventKey:"Summer workshop in Indiranagar", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"SummerWorkshop"],
[Events.EventKey:"Impressions & Expressions in MG Road", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"ImpressionAndExpression"],
[Events.EventKey:"Italian carnival in Electronic City", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"ItalianCarnival"]
]
}
}
Create properties in your destination viewController and use them like below
import UIKit
class DetailedEventViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var deatiledEvent: UILabel!
#IBOutlet weak var eventType: UILabel!
var myImage = UIImage?
var eventDetails = ""
var typeOfEvent = ""
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = myImage
deatiledEvent.text = eventDetails
eventType.text = typeOfEvent
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
and then in your first viewController you can access them like
let dest = segue.destinationViewController as! DetailedEventViewController
dest.eventDetails = nextScreenRow.eventName
dest.typeOfEvent = nextScreenRow.entryType
dest.myImage = UIImage(named: nextScreenRow.imageName)

Passing coredata from tableview to another tableview

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)
}
}

SWIFT: When i create a secondViewController, how to access to variables from original ViewController

When I go to my secondViewController using
let secondViewController:SecondViewController = SecondViewController()
self.presentViewController(secondViewController, animated: true, completion: nil)
I know I can send varibles to SECOND ONE using secondViewController.theNum = num, but while secondViewController is presented how to send varibles bar to the original ViewController.
Thing is I would like to start viewdidload() on original ViewController after this part of code is finished
self.dismissViewControllerAnimated(true, completion:nil)
Here are the full classes for two Views from a project where I pass data to a detail view and use a protocol/delegate method to return data to the first view:
View 1:
import UIKit
class Contacts: UITableViewController, dataUpdated {
//Declaring contact structure
struct contactInfo {
var name: String
var phoneNumber: String
}
var listOfContacts: [contactInfo] = []
var Duration = 100
//Sample contacts
var firstContact = contactInfo(name: "John Coffey" , phoneNumber: "(111) 111-1111")
var secondContact = contactInfo(name: "Cathy Kane" , phoneNumber: "(222) 222-2222")
//TableView delegates
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfContacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("contact", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = listOfContacts[indexPath.row].name
cell.detailTextLabel?.text = listOfContacts[indexPath.row].phoneNumber
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
listOfContacts.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
//ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem()
listOfContacts.append(firstContact)
listOfContacts.append(secondContact)
}
//Passing details to detail VC
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ToDetail" {
let indexPath = self.tableView.indexPathForSelectedRow()
let theSelectedRow = listOfContacts[indexPath!.row]
let theDestination = (segue.destinationViewController as ContactDetails)
theDestination.contactName = theSelectedRow.name
theDestination.contactPhone = theSelectedRow.phoneNumber
} else if segue.identifier == "ToInput" {
(segue.destinationViewController as ContactInput).delegate = self
}
}
override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
let fromContact = listOfContacts[sourceIndexPath.row]
listOfContacts.removeAtIndex(sourceIndexPath.row)
listOfContacts.insert(fromContact, atIndex: destinationIndexPath.row)
}
//Delegate method to update the array with new contact
func didUpdateContact(senderClass: AnyObject, aName: String, aPhoneNumber: String) {
var newContact = contactInfo(name: aName, phoneNumber: aPhoneNumber)
listOfContacts.append(newContact)
println(listOfContacts)
self.tableView.reloadData()
}
}
View2:
import UIKit
protocol dataUpdated:NSObjectProtocol {
func didUpdateContact(senderClass: AnyObject, aName: String, aPhoneNumber: String)
}
class ContactInput: UIViewController, UITextFieldDelegate {
//Properties
var name = ""
var phoneNumber = ""
var delegate: dataUpdated?
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var phoneField: UITextField!
//Textfield delegates
func textFieldShouldReturn(textField: UITextField!) -> Bool {
if textField.tag == 1 {
self.name = textField.text
}
else {
self.phoneNumber = textField.text
}
textField.resignFirstResponder()
return true
}
//Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.nameField.delegate = self
self.phoneField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if name != "" && phoneNumber != "" {
self.delegate!.didUpdateContact(self, aName: self.name, aPhoneNumber: self.phoneNumber)
}
}
}

Resources