Passing data between an object class and a ViewController (Swift) - ios

[WHAT I WANT] I want to develop a functionality that when I click on a button of an initial ViewController named BdaysVC (first image) a table view appears (second image) and when I click on a row of the tableView it goes back to the ViewController passing the activeSortingMode value. If I click on the opaque view it only dismisses the tableView without passing any value.
[WHAT I HAVE] The code that I have used to implement the tableView is:
class SortTableView: NSObject, UITableViewDelegate, UITableViewDataSource {
...
func createViews (frame:CGRect) {
// Creating an opaque view and a tableView and adding them above the BdaysVC
}
...
#objc func onClickTransparentView() {
// Dismissing the tableView when touching the opaque view
}
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
switch indexPath.row {
case 0:
// Change the activeSortingMode of BdaysVC to 0
case 1:
// Change the activeSortingMode of BdaysVC to 1
case 2:
// Change the activeSortingMode of BdaysVC to 2
case 3:
// Change the activeSortingMode of BdaysVC to 3
default:
print("sorting mode")
}
}
...
override init() {
super.init()
...
tableView.delegate = self
tableView.dataSource = self
...
}
}
And for the ViewController:
class BdaysVC: UIViewController {
...
var activeSortingMode: Int = 0
...
let sortTableView = SortTableView()
#IBAction func sortButtonClicked(_ sender: Any) {
sortTableView.createViews(frame: self.view.frame)
}
override func viewWillAppear(_ animated: Bool) {
...
retrieveSections(sortingMode: activeSortingMode)
}
override func viewDidLoad() {
super.viewDidLoad()
...
retrieveSections(sortingMode: activeSortingMode)
}
}
[PROBLEM] My problem is that I don't know how to change the activeSortingMode value of the ViewController when a cell of the tableView is selected and reload the ViewController with the method viewWillAppear().
I hope you can help me with this issue. Thanks in advance!

You can use delegate or closure for that
protocol ActiveSortingModeSelect {
func activeSortingModeSelected(_ index: Int)
}
class SortTableView: NSObject, UITableViewDelegate, UITableViewDataSource {
...
weak var delegate: ActiveSortingModeSelect!
func createViews (frame:CGRect) {
// Creating an opaque view and a tableView and adding them above the BdaysVC
}
...
#objc func onClickTransparentView() {
// Dismissing the tableView when touching the opaque view
}
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
delegate.activeSortingModeSelected(indexPath.row)
...
override init() {
super.init()
...
tableView.delegate = self
tableView.dataSource = self
...
}
}
class BdaysVC: UIViewController {
...
var activeSortingMode: Int = 0
...
let sortTableView = SortTableView()
#IBAction func sortButtonClicked(_ sender: Any) {
sortTableView.createViews(frame: self.view.frame)
}
override func viewWillAppear(_ animated: Bool) {
...
retrieveSections(sortingMode: activeSortingMode)
}
override func viewDidLoad() {
super.viewDidLoad()
...
sortTableView.delegate = self // Don't forget to set delegate
retrieveSections(sortingMode: activeSortingMode)
}
}
extension BdaysVC: ActiveSortingModeSelect {
func activeSortingModeSelected(_ index: Int) {
self.activeSortingMode = index
}
}

Related

How to bring UIImageView to foreground upon tapping a tableViewCell?

currently thumbnails are being shown in UITableViewCell and upon tapping a cell, I want the image to be shown in foreground with a cross/X button on right top to dismiss the image and show tableView. I have the following code in didSelectRow:
let hoverImage = UIImageView()
hoverImage.image = UIImage(named: "splashpt")
hoverImage.contentMode = .scaleAspectFit
self.view.addSubview(hoverImage)
hoverImage.center = self.view.center
hoverImage.layer.zPosition = 5
self.view.bringSubview(toFront: hoverImage)
Still the image doesn't show up. The computation is hitting this section of the code because I'm able to debug and step through this part of the code. But nothing shows up on screen. I'm using the zPosition AND bringSubview(toFront:) and neither of the seem to work for my requirement. Any help would be greatly appreciated. Thank you.
This is a Demo table view.On tapping the table view cells a view is poped up with close button. And on pressing the close button the pop up view is closed.
import UIKit
class ViewController: UITableViewController {
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 numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.textLabel?.text = "Happy"
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Cell\(indexPath.row) is selected")
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let popoverVC = storyBoard.instantiateViewControllerWithIdentifier("PopViewController") as! PopViewController
popoverVC.delegate = parentViewController as? InfoViewDelegate
let nav = UINavigationController(rootViewController: popoverVC)
nav.modalPresentationStyle = UIModalPresentationStyle.Popover
nav.navigationBar.hidden = true
self.presentViewController(nav, animated: true)
{
}
popoverVC.passingViewController = self
}
}
This is a PopUpViewController:
import UIKit
protocol InfoViewDelegate: class
{
func infoViewClicked(tag: Int)
}
class PopViewController :UIViewController
{
#IBOutlet weak var btnClose: UIButton!
var delegate = InfoViewDelegate?()
var passingViewController: UIViewController!
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.
}
override func viewWillAppear(animated: Bool) {
}
override func viewDidDisappear(animated: Bool) {
self.presentingViewController?.dismissViewControllerAnimated(true
, completion: {
})
}
/*
// 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.
}
*/
#IBAction func btnClicked(sender: UIButton) {
if(sender == self.btnClose)
{
self.delegate?.infoViewClicked(1)
self.presentingViewController?.dismissViewControllerAnimated(true
, completion: {
})
}
}
}

Unwind segue not unwinding

I'm trying to create a simple unwind segue but apparently I've made a mistake somewhere. The save button I would like to unwind reacts to pressing but doesn't unwind to the table view. Thanks in advance I appreciate it.
import UIKit
class NoteTableViewController: UITableViewController {
var notes = [Note]()
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
return cell
}
//ACTION
#IBAction func unwindToNoteList(sender: UIStoryboardSegue) {
if let sourceViewController = sender.source as? ViewController, let noteTaken = sourceViewController.noteTaken {
// Add a new meal.
let newIndexPath = IndexPath(row: notes.count, section: 0)
notes.append(noteTaken)
tableView.insertRows(at: [newIndexPath], with: .automatic)
}
}
}
and my view controller
import UIKit
import os.log
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var typeField: UITextField!
#IBOutlet weak var textDisplay: UILabel!
#IBOutlet weak var saveButton: UIBarButtonItem!
var noteTaken: Note?
func textFieldDidEndEditing(_ textField: UITextField) {
textDisplay.text = typeField.text
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard.
typeField.resignFirstResponder()
return true
}
override func viewDidLoad() {
super.viewDidLoad()
typeField.delegate = self
// Do any additional setup after loading the view, typically from a nib.
}
//NAV
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
// Configure the destination view controller only when the save button is pressed.
guard let button = sender as? UIBarButtonItem, button === saveButton else {
os_log("The save button was not pressed, cancelling", log: OSLog.default, type: .debug)
return
}
let note = typeField.text ?? ""
// Set the meal to be passed to MealTableViewController after the unwind segue.
noteTaken = Note(note: note)
}
#IBAction func cancelButton(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is how I create my unwind segues:
Write the code for the unwind segue in the first View Controller:
#IBAction func unwindSegue(Segue: UIStoryboardSegue) {
// Run code when the view loads up
}
Create the segue in main.storyboard:
Give the segue an identifier:
then call it in code:
#IBAction func UnwindButton(_ sender: UIButton) {
performSegue(withIdentifier: "UnwindSegue", sender: UIButton())
}
Hope this helps!!!

how to perform segue to a VC with Container

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.

Swift Redundant conformance

I am learning iOS. And now local database on iOS. I'm from Android and finding local DB a bit difficult to understand. I wrote a question which brought me several down votes (instead of simple use of CoreStore or Sync or MagicalRecord). I then started reading this tutorial. After downloading the sample project I'm getting Redundant conformance of 'BeerListViewController' to protocol 'UITableViewDataSource' error in BeerListViewController. Please tell me how can I get it solved.
Here is the code:
import UIKit
import Foundation
class BeerListViewController: UITableViewController {
#IBOutlet weak var sortByControl: UISegmentedControl!
#IBOutlet weak var searchBar: UISearchBar!
let sortKeyName = "name"
let sortKeyRating = "beerDetails.rating"
let wbSortKey = "wbSortKey"
//------------------------------------------
// Rating
var amRatingCtl: AnyObject!
let beerEmptyImage: UIImage = UIImage(named: "beermug-empty")!
let beerFullImage: UIImage = UIImage(named: "beermug-full")!
//#####################################################################
// MARK: - Initialization
required init(coder aDecoder: NSCoder) {
// Automatically invoked by UIKit as it loads the view controller from the storyboard.
amRatingCtl = AMRatingControl(location: CGPointMake(190, 10),
emptyImage: beerEmptyImage,
solidImage: beerFullImage,
andMaxRating: 5)
// A call to super is required after all variables and constants have been assigned values but before anything else is done.
super.init(coder: aDecoder)!
}
//#####################################################################
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Allows data to be passed to the new view controller before the new view is displayed.
// "destinationViewController" must be cast from its generic type (AnyObject) to the specific type used in this app
// (BeerDetailViewController) before any of its properties can be accessed.
let controller = segue.destinationViewController as? BeerDetailViewController
if segue.identifier == "editBeer" {
controller!.navigationItem.rightBarButtonItems = []
//------------------------------------------------------------------------------------
} else if segue.identifier == "addBeer" {
controller!.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel",
style: UIBarButtonItemStyle.Plain,
target: controller,
action: "cancelAdd")
controller!.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done",
style: UIBarButtonItemStyle.Done,
target: controller,
action: "addNewBeer")
}
}
//#####################################################################
// MARK: - UIViewController - Responding to View Events
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//------------------------------------------
// Sorting Key
if !(NSUserDefaults.standardUserDefaults().objectForKey(wbSortKey) != nil) {
// User's sort preference has not been saved. Set default to sort by rating.
NSUserDefaults.standardUserDefaults().setObject(sortKeyRating, forKey: wbSortKey)
}
// Keep the sort control in the UI in sync with the means by which the list is sorted.
if NSUserDefaults.standardUserDefaults().objectForKey(wbSortKey) as! String == sortKeyName {
sortByControl.selectedSegmentIndex = 1
}
//------------------------------------------
fetchAllBeers()
// Cause tableView(cellForRowAtIndexPath) to be called again for every visible row in order to update the table.
tableView.reloadData()
}
//#####################################################################
// MARK: - UIViewController - Managing the View
// viewDidLoad() is called after prepareForSegue().
override func viewDidLoad() {
super.viewDidLoad()
//------------------------------------------
tableView.contentOffset = CGPointMake(0, 44)
}
//#####################################################################
// MARK: - Action Methods
#IBAction func sortByControlChanged(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
NSUserDefaults.standardUserDefaults().setObject(sortKeyRating, forKey: wbSortKey)
fetchAllBeers()
tableView.reloadData()
case 1:
NSUserDefaults.standardUserDefaults().setObject(sortKeyName, forKey: wbSortKey)
fetchAllBeers()
tableView.reloadData()
default:
break
}
}
//#####################################################################
// MARK: - MagicalRecord Methods
func fetchAllBeers() {
}
//#####################################################################
func saveContext() {
}
//#####################################################################
}
//#####################################################################
// MARK: - Table View Data Source
extension BeerListViewController: UITableViewDataSource { // THE ERROR APPEARS HERE
//#####################################################################
// MARK: Configuring a Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//#####################################################################
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
//#####################################################################
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier)
configureCell(cell!, atIndex: indexPath)
return cell!
}
//#####################################################################
// MARK: Helper Methods
func configureCell(cell: UITableViewCell, atIndex indexPath: NSIndexPath) {
//------------------------------------------
// Rating
let ratingText = ""
let myRect = CGRect(x:250, y:0, width:200, height:50)
var ratingLabel = UILabel(frame: myRect)
if !(cell.viewWithTag(20) != nil) {
ratingLabel.tag = 20
ratingLabel.text = ratingText
cell.addSubview(ratingLabel)
} else {
ratingLabel = cell.viewWithTag(20) as! UILabel
}
//----------------------
ratingLabel.text = ratingText
}
//#####################################################################
// MARK: Inserting or Deleting Table Rows
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
//#####################################################################
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// When the commitEditingStyle method is present in a view controller, the table view will automatically enable swipe-to-delete.
if (editingStyle == .Delete) {
}
}
//#####################################################################
}
//#####################################################################
// MARK: - Search Bar Delegate
extension BeerListViewController: UISearchBarDelegate {
// MARK: Editing Text
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text != "" {
performSearch()
} else {
fetchAllBeers()
tableView.reloadData()
}
}
//#####################################################################
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchBar.showsCancelButton = true
}
//#####################################################################
// MARK: Clicking Buttons
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder()
searchBar.text = ""
searchBar.showsCancelButton = false
fetchAllBeers()
tableView.reloadData()
}
//#####################################################################
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// This method is invoked when the user taps the Search button on the keyboard.
searchBar.resignFirstResponder()
performSearch()
}
//#####################################################################
// MARK: Helper Methods
func performSearch() {
tableView.reloadData()
}
//#####################################################################
// MARK: - Bar Positioning Delegate
// UISearchBarDelegate Protocol extends UIBarPositioningDelegate protocol.
// Method positionForBar is part of the UIBarPositioningDelegate protocol.
// This delegate method is required to prevent a gap between the top of the screen and the search bar.
// That happens because, as of iOS 7, the status bar is no longer a separate area but is directly drawn on top of the view controller.
func positionForBar(bar: UIBarPositioning) -> UIBarPosition {
// Tell the search bar to extend under the status bar area.
return .TopAttached
}
//#####################################################################
}
UITableViewController conforms to UITableViewDataSource by definition.
Just delete the protocol conformance
extension BeerListViewController { ...

Swift 2 Nil Delegate

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.

Resources