So I want to create a IOS application that generates a group of students, adds them to a course and then shows students. I can show students in a list in a table view but now I want to let the user touch a student's name and be taken to a page with information about that student (name highest grade etc). The student class is flawless, the course works and the only problem I have is that I can't get a student from one view to the other.
Here's what I have so far:
//
// DataTableViewController.swift
// assignment8
//
import Foundation
import UIKit
class DataTableViewController: UITableViewController {
var delegate:StudentSelectionDelegate! = nil
var students = [Student]();
var course = Course();
// MARK: - UITableViewDataSource
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func didSelectStudent(controller:UITableViewController, student:Student!) {
controller.navigationController?.popViewControllerAnimated(true)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.course = courseStorage.getCourse();
self.students = course.getArrayOfStudentSortedByLastName();
return course.count;
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
let currentStudent = students[row];
if (delegate != nil) {
delegate.didSelectStudent(self,student:currentStudent)
}
else {
print ("delegate is nil :(");
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("studentCell", forIndexPath: indexPath)
cell.textLabel?.text = students[indexPath.row].lastName + ", " +
students[indexPath.row].firstName;
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
print("ping");
if segue.identifier == "studentSegue" {
let nextScene = segue.destinationViewController as! studentViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedStudent = students[indexPath.row]
print (selectedStudent.firstName);
nextScene.student = selectedStudent;
}
}
}
}
and
//
// DataViewController.swift
// assignment8
//
import UIKit
class DataViewController: UIViewController {
#IBOutlet weak var dataLabel: UILabel!
var dataObject: String = ""
let tableData = ["One","Two","Three"];
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.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.dataLabel!.text = dataObject
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int)
-> Int {
return self.tableData.count;
}
}
and
//
// studentViewController.swift
// assignment8
//
import UIKit
protocol StudentSelectionDelegate {
func didSelectStudent(controller: UITableViewController, student:Student)
}
class studentViewController: UIViewController {
var delegate = StudentSelectionDelegate.self;
var name = String();
var student = Student();
#IBOutlet weak var StudentName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func didSelectStudent(controller:UITableViewController, student:Student!) {
student.description;
print ("pong")
StudentName.text = student.firstName + " " + student.lastName;
controller.navigationController?.popViewControllerAnimated(true);
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// override func viewWillAppear(animated: Bool) {
// StudentName.text = name
// }
}
This is my storyboard so far.
So, any time I try clicking a student it will print the message that I've decided to use if the delegate is nil. So far I've tried looking at all the other answers on SO but none of them have fixed my issue.
To be able to send information from one view controller to another you should use segues. It seems like that's what you're doing according to the image. If you don't know how to use a segue, you can find a good answer here: Sending data with Segue with Swift
With segues you'll be able to set the delegate of the next view controller:
protocol MyDelegate {
func myFunction()
}
class FirstViewController: UIViewController, MyDelegate {
func myFunction() {
// do what the function does
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let secondVC = segue.destinationViewController as? SecondViewController {
secondVC.delegate = self
}
}
}
class SecondViewController: UIViewController {
var delegate: MyDelegate!
}
Before you segue to the second view controller (you're preparing for the segue), you set the delegate variable of SecondViewController to self, because FirstViewController conforms to MyDelegate protocol so it can be used there. Now, in SecondViewController you can use delegate.myFunction() and it will do whatever is written inside the FirstVC's function, because the FirstVC is SecondVC's delegate.
Related
see this gif
when I choose the city Med , it passed to the TableVC not to the FirstVC (MainVC)
can I do that ? segue to the mainVC with the data passed through
the container (TableVC) ?
here what I did so far
MainVC
Empty
TableVC
import UIKit
class passedViewController: UITableViewController {
#IBOutlet weak var passcelltow: UITableViewCell!
#IBOutlet weak var passcell: UITableViewCell!
var passedCity1 = "اختر المدينة الاولى"
var passedCity2 = "اختر المدينة الثانية"
override func viewDidLoad() {
super .viewDidLoad()
passcell.textLabel?.text = passedCity1
passcelltow.textLabel?.text = passedCity2
}
}
Table 1 with data to pass to the TableVC
import UIKit
class city2ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
var city2 = ["RUH" , "Med" , "Jed"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return city2.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
print(indexPath.row)
cell.textLabel?.text = city2[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "show", sender: city2[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let passing = segue.destination as! passedViewController
passing.passedCity2 = sender as! String
}
}
Table 2 is the same ..
commend error
0 1 2 Could not cast value of type 'UIViewController' (0x107a10288) to
'table_view_test_pass.passedViewController' (0x105dbfdf8). (lldb)
You can pass data via segues or protocols. Since you are using segues i will show you a complete example and how to do it the right way in Swift 3. Using only two ViewControllers.
Create two UITextFields in the main "ViewController".
Create a new view controller of type UIViewController call it "MainTabelViewController" and add a tableView in it. Select content Dynamic prototypes Style Grouped and create 1 prototype cell and add a UILabel to it for the city name. "Don't forget the put the cell identifier name". I called it "cell".
Add the delegates and data sources to the class and add its functions like in code.
Create a segue from the main view controller to the main table view controller. And create another segue the opposite direction. "Don't forget the put the segue identifier names" I called them "toCity" & "toMain"
Create a "CityTableViewCell" controller of type UITableViewCell and create an IBOutlet of UILabel type where you will save the city name in as a text.
Edit this part in the AppDelegate.swift To delete the city names saved using in the UserDefaults every time the app is launched. So i wont populate the UITextFields randomly every time.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var userDefaults: UserDefaults!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
userDefaults = UserDefaults.standard
userDefaults.removeObject(forKey: "City One")
userDefaults.removeObject(forKey: "City Two")
return true
}
This is the ordinary main ViewController.swift where you have your UITextFields in. I distinguish which UITextField did the user click on using the tags. You need to add also the UITextFieldDelegate protocol to be able to use the the textFieldDidBeginEditing function. And i also save the selected city names using UserDefaults class to call them when user chooses the other city.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var cityOneLabel: UITextField!
#IBOutlet var cityTwoLabel: UITextField!
#IBOutlet var continueButton: UIButton!
var selectedCityOne = ""
var selectedCityTwo = ""
var userDefaults: UserDefaults!
override func viewDidLoad() {
super.viewDidLoad()
cityOneLabel.delegate = self
cityTwoLabel.delegate = self
cityOneLabel.tag = 1
cityTwoLabel.tag = 2
continueButton.isEnabled = false
}
override func viewDidAppear(_ animated: Bool) {
userDefaults = UserDefaults.standard
cityOneLabel.text = selectedCityOne
cityTwoLabel.text = selectedCityTwo
if selectedCityOne != "" {
userDefaults.set(selectedCityOne, forKey: "City One")
} else {
cityOneLabel.text = userDefaults.string(forKey: "City One")
}
if selectedCityTwo != "" {
userDefaults.set(selectedCityTwo, forKey: "City Two")
} else {
cityTwoLabel.text = userDefaults.string(forKey: "City Two")
}
if cityOneLabel.text != "" && cityTwoLabel.text != "" {
continueButton.isEnabled = true
} else {
continueButton.isEnabled = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func continueButtonAction(_ sender: UIButton) {
//Later on continue after selecting the cities
}
func textFieldDidBeginEditing(_ textField: UITextField) {
performSegue(withIdentifier: "toCity", sender: textField.tag)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toCity" {
guard let cityVC = segue.destination as? MainTableViewController else {
return
}
cityVC.selectedTextField = sender as! Int
}
}
}
In the CityTabelViewCell.swift add the IBOutlet UILabel for the city name.
import UIKit
class CityTableViewCell: UITableViewCell {
#IBOutlet var cityNameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
For the MainTabelViewController.swift write this:
Here is where i create an array of strings to populate my table view UILabels with.
import UIKit
class MainTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var cityTabelView: UITableView!
var cityNamesArray = ["Cairo", "Alexandria", "Suez"]
var selectedTextField = Int()
var selectedCityName = ""
override func viewDidLoad() {
super.viewDidLoad()
cityTabelView.delegate = self
cityTabelView.dataSource = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CityTableViewCell
cell.cityNameLabel.text = cityNamesArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cityNamesArray.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCityName = cityNamesArray[indexPath.row]
performSegue(withIdentifier: "toMain", sender: self)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var title = ""
if selectedTextField == 1 {
title = "City One"
} else if selectedTextField == 2 {
title = "City Two"
}
return title
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMain" {
guard let mainVC = segue.destination as? ViewController else {
return
}
if selectedTextField == 1 {
mainVC.selectedCityOne = selectedCityName
} else if selectedTextField == 2 {
mainVC.selectedCityTwo = selectedCityName
}
}
}
}
This is how my layout looks like. Try it. I just added a continue button too if the user will have to go to another UIViewController after selecting the two cities.
If you want to segue to MainVC, you should instantiate a view controller from that class in prepare for segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let passing = segue.destination as! ViewController
passing.passedCity2 = sender as! String
}
Change ViewController to whatever the name of your class is for MainVC.
If you want to go back to the Parent View, you should be using an unwind-segue.
For that you must create the unwind segue method in the Parent View like this
#IBAction func unwindSegueFromChild(segue: UIStoryboardSegue){
// This code executes when returning to view
}
And in your child view you must create the unwind segue ctrl+dragging
There a dropdown appears and you select unwindSegueFromChild
Once you've done that, you must assign the unwind segue an identifier and programmatically perform it like a normal segue.
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.
I am trying to setup a popover view containing a textfield and a tableview, but I couldn't make the tableview to show the data. It would be much appreciated if you could help me on this.
On the main ViewController, I put a label to trigger the segue of popover,
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var textField: UITextField!
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.
}
#IBAction func popover(sender: AnyObject) {
self.performSegueWithIdentifier("ShowDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowDetails" {
if let controller = segue.destinationViewController as? UIViewController {
controller.popoverPresentationController!.delegate = self
controller.preferredContentSize = CGSize(width: 320, height: 50)
}
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
}
A PopoverCell is setup for the prototype cell,
import UIKit
class PopoverCellTableViewCell: UITableViewCell {
#IBOutlet weak var AreaCellLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
A PopoverControllerView is set for the popover itself.
import UIKit
class PopoverViewController: UIViewController, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {
var areas = [Area]()
// #IBOutlet weak var NewArea: UITextField!
// #IBOutlet weak var SaveNewArea: UIButton!
#IBOutlet weak var subtableView: UITableView!
override func viewDidLoad() {
subtableView.dataSource = self
subtableView.delegate = self
super.viewDidLoad()
LoadsampleArea()
// Do any additional setup after loading the view.
}
func LoadsampleArea () {
let area1 = Area(AreaName:"Moountain")!
let area2 = Area(AreaName:"ByHill")!
let area3 = Area(AreaName:"Yard")!
areas += [area1, area2, area3]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return areas.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "AreaCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! PopoverCellTableViewCell
let area = areas[indexPath.row]
cell.AreaCellLabel.text = area.AreaName
dismissViewControllerAnimated(true, completion:nil)
return cell
}
}
and a simple data file to put the data.
import UIKit
class Area {
var AreaName: String
init? (AreaName: String) {
self.AreaName = AreaName
if AreaName.isEmpty {
return nil
}
}
}
Where is your UITableView object in your PopoverViewController class ? I can't see any reference to it.
Maybe your didn't copy-paste it since the textfield is commented too, in this case I'll suggest to check if the delegate an datasource are set property.
I am really struggling to pass data from SecondViewController to ActivityFormTableViewController.
get this error: 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'MajorActivity''
Code for two classes follow:
Any help would be received with gratitude.
//
// SecondViewController.swift
// LinkByActivity
//
// Created by Jeremy Andrews on 2015/06/10.
// version update 23/06/2015
// Copyright (c) 2015 Jeremy Andrews. All rights reserved.
//
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
let textCellIdentifier = "TextCell"
var catRet = XnYCategories.mainCats("main")
var activityDictionary = [String : [String]]()
var key1:String!
#IBAction func ActivityMainCats(segue:UIStoryboardSegue) {
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// MARK: UITextFieldDelegate Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return catRet.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! UITableViewCell
let row = indexPath.row
cell.textLabel?.text = catRet[row]
return cell
}
// MARK: UITableViewDelegate Methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
var row = indexPath.row
let key1 = catRet[row]
println(key1)
performSegueWithIdentifier("MajorActivity", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "MajorActivity") {
var svc = segue.destinationViewController as! ActivityFormTableViewController;
svc.key2 = key1
println(key1)
}
}
}
//
// ActivityFormTableViewController.swift
// LinkByActivity
//
// Created by Jeremy Andrews on 2015/07/24.
// Copyright (c) 2015 Jeremy Andrews. All rights reserved.
//
import UIKit
class ActivityFormTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView2: UITableView!
var key2:String!
var catRet2 = XnYCategories.mainCats("Sport")
let textCellIdentifier = "TextCell2"
var activityDictionary = [String : [String]]()
override func viewDidLoad() {
super.viewDidLoad()
println(key2)
var catRet2 = XnYCategories.mainCats(key2)
println(catRet2)
tableView.delegate = self
tableView.dataSource = self
}
// MARK: UITextFieldDelegate Methods
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//var catRet2 = XnYCategories.mainCats(key2)
return catRet2.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! UITableViewCell
let row = indexPath.row
cell.textLabel?.text = catRet2[row]
return cell
}
// MARK: UITableViewDelegate Methods
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
var row = indexPath.row
let activityKey = "CellNo_" + "famNam_" + key2
activityDictionary = [activityKey: ["TheForm", "l1", "etc"]]
//println(activityDictionary)
}
}
You need to create a UINavigationController in your prepareForSegue method because it appears as that's what you have on your storyboard. Then you need to create an instance of the controller that you want the navigation controller to show and assign your properties to that.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "MajorActivity") {
let activityFormNavController = segue.destinationViewController as! UINavigationController
let svc = activityFormNavController.topViewController as! ActivityFormTableViewController
svc.key2 = key1
println(key1)
}
}
Storyboard Example:
ViewController.swift
import UIKit
class ViewController: UIViewController {
var someString : 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.
}
#IBAction func fireSegueBttnTouched(sender: AnyObject) {
// set my local instance variable to some value to pass
someString = "Stack Overflow Is Great!"
performSegueWithIdentifier("next", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "next" {
// Create a UINavigationController instance first b/c that's where the segue goes
let nextNavVc = segue.destinationViewController as! UINavigationController
// Create an instance of the top view controller belonging to the above crated navigation controller
let nextVc = nextNavVc.topViewController as! SecondViewController
// Assign the instance variable from this view controller to the variable on the view controller nextVc
nextVc.passedString = someString
}
}
}
SecondViewController.swift
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var outputLabel: UILabel!
var passedString : String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
if passedString != nil {
outputLabel.text = passedString!
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Simulator Screenshots:
I'm learning swift, and i'm having problems trying to fire a segue when a TableViewCell is touched, which is supposed to pass an url to a second view that for the moment just a displays it in a label.
i Dynamically create ( i've seen people use Programmatically, which is probably the right word) every single Cell, so, in the storyboard i don't have any object to link to another view except the view itself... and that's what i did.
So i connected the first view controller to the second, and added the code to perform the segue.
i'm not sure if it's right, my knowledge comes from tutorials that didn't exactly explain what i wanted to do.
down there there's the code of the two views.
first view
import UIKit
protocol sendInfoDelegate{
func userDidEnterInfo( WhichInfo info : String)
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableData = []
#IBOutlet weak var redditListTableView: UITableView!
var selectedCellURL : String?
var delegate : sendInfoDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// change the link to change the json source
getRedditJSON("http://www.reddit.com/.json")
}
//
//Creates a connection via a task (networktask) then parses the json
//
func getRedditJSON(whichReddit : String){
let mySession = NSURLSession.sharedSession()
let url: NSURL = NSURL(string: whichReddit)
let networkTask = mySession.dataTaskWithURL(url, completionHandler : {data, response, error -> Void in
var err: NSError?
var theJSON = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSMutableDictionary
let results : NSArray = theJSON["data"]!["children"] as NSArray
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.redditListTableView.reloadData()
})
})
networkTask.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//needs to be implemented
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
//creates the whole table
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
let redditEntry : NSMutableDictionary = self.tableData[indexPath.row] as NSMutableDictionary
cell.textLabel?.text = redditEntry["data"]!["title"] as? String
cell.detailTextLabel?.text = redditEntry["data"]!["author"] as? String
return cell
}
// action to be taken when a cell is selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let redditEntry : NSMutableDictionary = self.tableData[indexPath.row] as NSMutableDictionary
self.selectedCellURL = redditEntry["data"]!["url"] as? String
self.performSegueWithIdentifier("passInfo" , sender: indexPath)
println(self.selectedCellURL!)
if delegate != nil {
let information:String = self.selectedCellURL!
println("ciao")
delegate?.userDidEnterInfo(WhichInfo: information)
self.navigationController?.popViewControllerAnimated(true)
}
second view
import UIKit
class WebPageController : UIViewController, sendInfoDelegate {
var infoFromSVC: String?
#IBOutlet weak var labelVC: UILabel!
func userDidEnterInfo(WhichInfo info: String) {
self.infoFromSVC = info
labelVC.text = infoFromSVC
}
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.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "passInfo"{
let firstVController : ViewController = segue.destinationViewController as ViewController
firstVController.delegate = self
}
}
}
Thanks.
To pass any data to second view controller you need to implement prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) method in your first view controller and here pass any data to your second view controller through segue.destinationViewController object.
for example
// this method must be in first view controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "passInfo" {
var secondViewController : SecondViewController = segue.destinationViewController as SecondViewController
var indexPath = self.tableview.indexPathForSelectedRow() //get index of data for selected row
secondViewController.data = self.dataArray.objectAtIndex(indexPath.row) // get data by index and pass it to second view controller
}
}
The code for getting data in second view controller
override func viewDidLoad() {
super.viewDidLoad()
self.label.text = self.data
}
The data variable must be defined as a property of your second view controller.