Updating labels on secondViewController with data from tableViewController - ios

I have a tableView as initial controller and few labels in secondViewController.
When I create a cell with data I want, the idea is to display that data in the secondViewController labels. All works fine, BUT, the labels in the secondVC update only when I hit the back button, to go back to the table view and select the row again.
How can I update the data displayed in the secondVC on the first tap in the tableview cell?
enter code here
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var titles = [String]()
var subjects = [String]()
var previews = [String]()
var textFieldsText = [UITextField!]()
var selectedTitle: String!
var selectedSubject: String!
var selectedPreview: String!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "addTitle")
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = titles[indexPath.row]
cell.detailTextLabel?.text = subjects[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedTitle = self.titles[indexPath.row]
selectedSubject = self.subjects[indexPath.row]
selectedPreview = self.previews[indexPath.row]
tableView.reloadData()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showPreview" {
let dataToPass = segue.destinationViewController as! previewViewController
dataToPass.titlesString = selectedTitle
dataToPass.subjectsString = selectedSubject
dataToPass.previewsString = selectedPreview
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func addTitle() {
let addAlert = UIAlertController(title: "New Title", message: "Add new title, subject and a short preview", preferredStyle: .Alert)
addAlert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
addAlert.addTextFieldWithConfigurationHandler {[unowned self] textField in
textField.placeholder = "Add Title"
textField.textAlignment = .Center
self.textFieldsText.append(textField)
}
addAlert.addTextFieldWithConfigurationHandler { textField in
textField.placeholder = "Add Subject"
textField.textAlignment = .Center
self.textFieldsText.append(textField)
}
addAlert.addTextFieldWithConfigurationHandler { textField in
textField.placeholder = "Add Short Preview"
textField.textAlignment = .Center
self.textFieldsText.append(textField)
}
addAlert.addAction(UIAlertAction(title: "Done", style: .Default){ _ in
self.titles.append(self.textFieldsText[0].text!)
self.subjects.append(self.textFieldsText[1].text!)
self.previews.append(self.textFieldsText[2].text!)
self.tableView.reloadData()
self.textFieldsText.removeAll()
})
presentViewController(addAlert, animated: true, completion: nil)
}
}
class previewViewController: UIViewController {
#IBAction func readButton(sender: UIButton) {
}
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var subjectLabel: UILabel!
#IBOutlet weak var shortPreviewLabel: UITextView!
var titlesString: String!
var subjectsString: String!
var previewsString: String!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Save, target: self, action: "saveChanges")
titleLabel.text = titlesString
subjectLabel.text = subjectsString
shortPreviewLabel.text = previewsString
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
let dataToDetail = segue.destinationViewController as! detailViewController
dataToDetail.textViewString = self.previewsString
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

If I understand your question right, this may help:
use this didSelectRowAtIndexPath:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("showPreview", sender: indexPath.row)
}
use this prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showPreview" {
let destinationViewController = segue.destinationViewController as! previewViewController
if let index = sender as? Int {
destinationViewController.titlesString = self.titles[index]
destinationViewController.subjectsString = self.subjects[index]
destinationViewController.previewsString = self.previews[index]
}
}
}
And you need to have a segue from ViewController to previewViewController called "showPreview". Like this:

Related

How do I get the document id by clicking the button on the tableview cell?

I am using a xib file apart from the main storyboard in my view controller for displaying a post item, and there is comment button, upon being clicked it should go to another page where the list of comments related to that post is available. for that I need to pass the documentId of the post as well so that the accurate segue operation could be performed.
I have tried my things by searching google but till now nothing had worked for me.
if any more details are required please let me know
HomeViewController Swift Class
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
var posts = [Post]()
var db: Firestore!
var postKey:String = ""
private var documents: [DocumentSnapshot] = []
//public var posts: [Post] = []
private var listener : ListenerRegistration!
var detailView: Post?
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
self.navigationController?.navigationBar.isTranslucent = false
tableView = UITableView(frame: view.bounds, style: .plain)
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
tableView.backgroundColor = UIColor(white: 0.90,alpha:1.0)
view.addSubview(tableView)
var layoutGuide:UILayoutGuide!
if #available(iOS 11.0, *) {
layoutGuide = view.safeAreaLayoutGuide
} else {
// Fallback on earlier versions
layoutGuide = view.layoutMarginsGuide
}
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
retrieveAllPosts()
//checkForUpdates()
postKey = detailView!._documentId
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.set(post: posts[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = self.posts[indexPath.row]
performSegue(withIdentifier: "toCommentsList", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//segue.forward(posts, to: segue.destination)
guard let details = segue.destination as? CommentListViewController,
let index = tableView.indexPathForSelectedRow?.row
else {
return
}
// details.detailView = posts[index]
}
//I tried to connect this action to the button in the XIB file but not able to do so.
#IBAction func toCommentsSection(_ sender: Any) {
print(postKey + "hello")
// let postId11 = detailView?._documentId
performSegue(withIdentifier: "toCommentsList", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var vc = segue.destination as! CommentListViewController
vc.postId = postKey
}
}
PostViewCell Class
class PostTableViewCell: UITableViewCell {
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var subtitleLabel: UILabel!
#IBOutlet weak var postTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// profileImageView.layer.cornerRadius = profileImageView.bounds.height / 2
// profileImageView.clipsToBounds = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func set(post:Post) {
if let userprofileImagUrl = post._postuserprofileImagUrl,
let imageUrl = URL(string: userprofileImagUrl) {
ImageService.getImage(withURL: imageUrl) { image in
self.profileImageView.image = image
}
}
usernameLabel.text = post._username
postTextLabel.text = post._postContent
subtitleLabel.text = post._postcategory
}
}
In PostTableViewCell create outlet of comment buttons
class PostTableViewCell: UITableViewCell {
#IBOutlet weak var btnComment: UIButton!
now in cellForRowAtIndex do add following line too
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.btnComment.tag = indexPath.row
cell.btnComment.addTarget(self, action: #selector(self. toCommentsSection(sender:)) , for: .touchUpInside)
cell.set(post: posts[indexPath.row])
return cell
}
and in
#IBAction func toCommentsSection(_ sender: Any) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post.postKey // or what key value it is
print(postKey + "hello")
// let postId11 = detailView?._documentId
performSegue(withIdentifier: "toCommentsList", sender: self)
}

Get values from a view controller's text field

I have 2 view controllers and a swift file. I wish to pass the data from one view controller to the other without using segue or presenting the other view controller.
View controller:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var questions:[Question] = []
var sub = ""
var send = ""
var det = ""
#IBOutlet weak var questionsender: UISegmentedControl!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questions.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "forumcell", for: indexPath) as! ForumTableViewCell
cell.questionsubject.text = questions[indexPath.row].subject
cell.sender.text = questions[indexPath.row].sender
return cell
}
}
Swift file:
import Foundation
class Question
{
var subject = ""
var descript = ""
var sender = ""
init(subject : String, descrip: String,sender : String)
{
self.sender=sender
self.descript=descrip
self.subject=subject
}
}
Second view controller:
import UIKit
class AddVC: UIViewController,UITextFieldDelegate {
var qsender = ""
var subject = ""
var details = ""
#IBAction func postBttn(_ sender: Any) {
if questiondetails.text == "" || question_sender.text == "" || question_subject.text == ""
{
let alert = UIAlertController(title: "Invalid!", message: "One of the fields has not been entered", preferredStyle: .alert)
let bttn = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(bttn)
}
else
{
qsender = question_sender.text
subject = question_subject.text
details = questiondetails.text
let q=Question(subject: subject, descrip: details, sender: qsender)
let v = ViewController()
v.send = qsender
v.sub = subject
v.det = details
dismiss(animated: true, completion: nil)
}
}
#IBAction func closeBttn(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBOutlet weak var question_subject: UITextView!
#IBOutlet weak var question_sender: UITextView!
#IBOutlet weak var closeBttn: UIButton!
#IBOutlet weak var questiondetails: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
question_subject.placeholderText="Sender"
question_subject.placeholderText="Subject"
questiondetails.placeholderText="Description"
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(swiped(_ :)))
swipeDown.direction = .down
self.view.addGestureRecognizer(swipeDown)
}
func swiped(_ gesture:UISwipeGestureRecognizer)
{
dismiss(animated: true, completion: nil)
}
}
The object v I created for View Controller cannot update the data members through the AddVC class.
in ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! AddVC
destination.callbackFromAddVC = { stringData in
// use stringData
}
}
in AddVC:
var callbackFromAddVC: ((String) -> Void)? = nil
func swiped(_ gesture:UISwipeGestureRecognizer)
{
self.callbackFromAddVC?("myStringData that needs to be transferred")
dismiss(animated: true, completion: nil)
self.callbackFromAddVC = nil
}
Add this line to ViewController:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
static let viewControllerSegueIdentifier: String = "ViewController"
Make sure that the viewControllerSegueIdentifier string matches your segue identifier.
Then make these edits to AddVC:
#IBAction func postBttn(_ sender: Any) {
if questiondetails.text == "" || question_sender.text == "" || question_subject.text == ""
{
let alert = UIAlertController(title: "Invalid!", message: "One of the fields has not been entered", preferredStyle: .alert)
let bttn = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(bttn)
}
else
{
qsender = question_sender.text
subject = question_subject.text
details = questiondetails.text
dismiss(animated: true, completion: {
goToAddScreen(segueIdentifier: ViewController.viewControllerSegueIdentifier)
})
}
}
Then add these 2 methods:
func goToAddScreen(segueIdentifier: String) {
performSegue(withIdentifier: segueIdentifier, sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == ViewController.viewControllerSegueIdentifier {
guard let controller = segue.destination as? ViewController else {
return
}
let q=Question(subject: subject, descrip: details, sender: qsender)
controller.questions.append(q)
}
}

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

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

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)

How to do Unit Test of segue in iOS 9

I had searched over the Internet for a couple of days without exact example hit my case. For simple class. I had created Unit test.I want to do Unit Testing on segue and unwind segue.
How can I do that?
ProfileTableViewController is a controller of left-hand-sided.
SeeDetailViewController is a controller of right-hand-sided.
ProfileTableViewController :
import UIKit
class ProfileTableViewController: UITableViewController {
var profiles = [Profile]();
var profileNew : Profile?;
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profiles.count;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ProfileTableViewCell";
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ProfileTableViewCell
let profile = profiles[indexPath.row];
cell.nameLabel.text = profile.name;
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true);
let row = indexPath.row;
print("Row:\(row)");
print(profiles[row].name , profiles[row].age);
performSegueWithIdentifier("segueTest", sender: row);
}
// Mark: Actions
#IBAction func backFromOtherController(segue: UIStoryboardSegue) {
NSLog("I'm back from other controller!")
print(profileNew?.name);
//add the new profile
if(profileNew != nil){
profiles += [profileNew!];
//update the tableview
tableView.reloadData();
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if(segue.identifier == "segueTest"){
let svc = segue.destinationViewController as! SeeDetailViewController
let rowid = sender as! Int;
svc.NamePassed = profiles[rowid].name;
svc.AgePassed = profiles[rowid].age;
svc.DescPassed = profiles[rowid].description;
svc.SpecPassed = profiles[rowid].specialty;
}
}
}
SeeDetailViewController :
import UIKit
public class SeeDetailViewController: UIViewController {
// Mark: Properties
#IBOutlet weak var NameLabel: UILabel!
#IBOutlet weak var AgeLabel: UILabel!
#IBOutlet weak var SpecialtyLabel: UILabel!
#IBOutlet weak var descTextView: UITextView!
var NamePassed : String!;
var AgePassed : Int!;
var SpecPassed : String!;
var DescPassed : String!;
override public func viewDidLoad() {
super.viewDidLoad()
NameLabel.text = NamePassed;
let myString = String(AgePassed);
AgeLabel.text = myString;
SpecialtyLabel.text = SpecPassed;
descTextView.text = DescPassed;
}
override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Mark: Actions
#IBOutlet weak var HitCall: UIButton!
#IBAction func alertControllerAction(sender: AnyObject) {
if(sender.tag == 0 ){
print("Touch down!");
let alertController = UIAlertController(title: "Hello!", message: "My name is \(NamePassed)", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action:UIAlertAction!) in
print("you have pressed the Cancel button");
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action:UIAlertAction!) in
print("you have pressed OK button");
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true, completion:nil)
}
}
/*
// 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.
}
*/
}
An easy way to unit test a view controller segue (although it breaks a bit of abstraction) is the following:
Create a variable, say, calledSegue which initially has a nil value.
Override performSegueWithIdentifier: function of your target view controller so that it sets calledSegue to the called segue identifier. Make sure that you also call super.performSegueWithIdentifier: within the overridden function in order to retain the original function's behaviour.
Create a unit test that check that calledSegue is set to the expected segue identifier under a test condition.
As said in this post you can use undocumented API to get the segues. And than you can write your tests like this:
class MyViewControllerTests: XCTestCase {
var SUT: MyViewController!
override func setUp() {
super.setUp()
SUT = UIStoryboard(name: "MyStoryboard", bundle: Bundle(for: MyViewController.self)).instantiateViewController(withIdentifier:String(describing: MyViewController.self)) as! MyViewController
let _ = SUT.view
}
override func tearDown() {
SUT = nil
super.tearDown()
}
// Mark: - Test Methods
func testSegues() {
let identifiers = segues(ofViewController: SUT)
XCTAssertEqual(identifiers.count, 2, "Segue count should equal two.")
XCTAssertTrue(identifiers.contains("ExitSegueIdentifier"), "Segue ExitSegueIdentifier should exist.")
XCTAssertTrue(identifiers.contains("ShowDetailViewController"), "Segue ShowDetailViewController should exist.")
}
// Mark: - Helper Methods
func segues(ofViewController viewController: UIViewController) -> [String] {
let identifiers = (viewController.value(forKey: "storyboardSegueTemplates") as? [AnyObject])?.flatMap({ $0.value(forKey: "identifier") as? String }) ?? []
return identifiers
}
}

Resources