Swift Redundant conformance - ios

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 { ...

Related

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

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

tableView reloadData doesn't work, delegate methods

I am trying to create new category in 1 view controller (AddCategoryViewController) and show it in table view controller (CategoryViewController). But there's an issue with reloading data.
New category item shows only after turning on and off the app, even when there is tableView.reloadData().
I tried to change the title of navigation in addButtonPressed function and the title changes immediately.
When I was using UIAlertView to add data, tableView.reloadData() worked. So I guess it's something with 2 view controllers and delegate methods?
Thanks for your help <3
show item:
import UIKit
import CoreData
class CategoryViewController: UITableViewController {
#IBOutlet weak var navigation: UINavigationItem!
var categoryArray = [Category]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
loadCategory()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categoryArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "CategoryItemCell")
cell.textLabel?.text = categoryArray[indexPath.row].name
if let randomColor = categoryArray[indexPath.row].color {
cell.textLabel?.textColor = UIColor(hex: randomColor)
}
return cell
}
// MARK: - Table view data source
#IBAction func addPressed(_ sender: UIBarButtonItem) {
let addCategoryVC = storyboard?.instantiateViewController(withIdentifier: "AddCategoryViewController") as! AddCategoryViewController
addCategoryVC.delegate = self
present(addCategoryVC, animated: true, completion: nil)
}
// MARK: - CoreData methods
func saveCategory() {
do {
try context.save()
} catch {
print("Save error: \(error)")
}
tableView.reloadData()
}
func loadCategory(with request: NSFetchRequest<Category> = Category.fetchRequest()) {
do {
categoryArray = try context.fetch(request)
} catch {
print("Load error: \(error)")
}
tableView.reloadData()
}
func addCategory(name: String, description: String) {
let newCategory = Category(context: context.self)
newCategory.name = name
newCategory.descriptionOfCategory = description
newCategory.color = UIColor.random().toHex
saveCategory()
print("name form func: \(name)")
print("description from func: \(description)")
}
}
// MARK: AddCateogry delegate methods
extension CategoryViewController: AddCategoryDelegate {
func addButtonPressed(name: String, description: String) {
addCategory(name: name, description: description)
navigation.title = "I have changed!"
}
}
Add item:
import UIKit
protocol AddCategoryDelegate {
func addButtonPressed(name: String, description: String)
}
class AddCategoryViewController: UIViewController {
var delegate : AddCategoryDelegate!
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var descriptionTextField: UITextField!
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 addCategoryButtonPressed(_ sender: UIButton) {
delegate.addButtonPressed(name: nameTextField.text!, description: descriptionTextField.text!)
dismiss(animated: true, completion: nil)
}
}
You only save the category to coredata inside addCategory , but you have to add the item to the array also , or call loadCategory before tableView.reloadData() inside saveCategory

Getting black screen on using tab bar while searching using SearchController

I have an app with a tab bar controller embedded in a navigation controller. The app has 2 tabs, the first one(search) has a search bar implemented using the UISearchController. If I switch from this tab to the other tab(downloads) while I'm searching, to the other tab two things happen -
The navigation bar in the second tab(downloads) disappears
When i come back to the first tab(search), it shows a black screen
I have done all this using the storyboard.
this is my SearchViewController
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate{
//MARK: Variables
var papers = [Paper]()
var filteredPapers = [Paper]()
let searchController = UISearchController(searchResultsController: nil)
// MARK: Outlets
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet var table: UITableView!
#IBOutlet weak var loadingMessageLabel: UILabel!
#IBOutlet weak var retryButton: UIButton!
//MARK: Actions
#IBAction func retryButton(sender: UIButton) {
self.loadingMessageLabel.hidden = false
self.loadingMessageLabel.text = "While the satellite moves into position..."
self.activityIndicator.hidden = false
self.activityIndicator.startAnimating()
self.retryButton.hidden = true
self.getPapersData()
}
// MARK: Table View
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If in searching mode, then return the number of results else return the total number
// if searchController.active && searchController.searchBar.text != "" {
if searchController.active {
return filteredPapers.count
}
return papers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let paper: Paper
// if searchController.active && searchController.searchBar.text != "" {
if searchController.active {
paper = filteredPapers[indexPath.row]
} else {
paper = papers[indexPath.row]
}
if let cell = self.table.dequeueReusableCellWithIdentifier("Cell") as? PapersTableCell {
cell.initCell(paper.name, detail: paper.detail)
print(cell)
return cell
}
return PapersTableCell()
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let downloadButton = UITableViewRowAction(style: .Normal, title: "Download") { action, index in
var url = String(self.papers[indexPath.row].url)
url = url.stringByReplacingOccurrencesOfString(" ", withString: "%20")
print(url)
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
// Spinner in cell
// var selectCell = self.table.cellForRowAtIndexPath(indexPath) as? PapersTableCell
// selectCell!.downloadSpinner.hidden = false
// Dismiss the download button
self.table.editing = false
Alamofire.download(.GET, url, destination: destination).response { _, _, _, error in
if let error = error {
print("Failed with error: \(error)")
} else {
print("Downloaded file successfully")
}
// selectCell?.downloadSpinner.hidden = true
}
}
downloadButton.backgroundColor = UIColor(red:0.30, green:0.85, blue:0.39, alpha:1.0)
return [downloadButton]
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// the cells you would like the actions to appear needs to be editable
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// you need to implement this method too or you can't swipe to display the actions
}
// MARK: Search
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredPapers = papers.filter { paper in
let categoryMatch = (scope == "All") || (paper.exam == scope)
return categoryMatch && paper.name.lowercaseString.containsString(searchText.lowercaseString)
}
table.reloadData()
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
// MARK: Defaults
override func viewDidLoad() {
super.viewDidLoad()
self.getPapersData()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
table.tableHeaderView = searchController.searchBar
searchController.searchBar.scopeButtonTitles = ["All", "ST1", "ST2", "PUT", "UT"]
searchController.searchBar.delegate = self
activityIndicator.startAnimating()
}
override func viewWillDisappear(animated: Bool) {
// if searchController.active {
self.searchController.resignFirstResponder()
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: API call
func getPapersData(){
Alamofire.request(.GET, "http://silive.in/bytepad/rest/api/paper/getallpapers?query=")
.responseJSON { response in
self.activityIndicator.stopAnimating()
self.activityIndicator.hidden = true
// If the network works fine
if response.result.isFailure != true {
self.loadingMessageLabel.hidden = true
self.table.hidden = false
//print(response.result) // result of response serialization
let json = JSON(response.result.value!)
for item in json {
// Split the title on the . to remove the extention
let title = item.1["Title"].string!.characters.split(".").map(String.init)[0]
let category = item.1["ExamCategory"].string
let url = item.1["URL"].string
let detail = item.1["PaperCategory"].string
let paper = Paper(name: title, exam: category!, url: url!, detail: detail!)
self.papers.append(paper)
}
self.table.reloadData()
}
// If the network fails
else {
self.retryButton.hidden = false
self.loadingMessageLabel.text = "Check your internet connectivity"
}
}
}
}
And this is my DownloadViewController
import UIKit
import QuickLook
class DownloadViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, QLPreviewControllerDataSource {
var items = [(name:String, url:String)]()
#IBOutlet weak var downloadsTable: UITableView!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(items[indexPath.row].url)
// performSegueWithIdentifier("DocumentViewSegue", sender: items[indexPath.row].url)
let previewQL = QLPreviewController() // 4
previewQL.dataSource = self // 5
previewQL.currentPreviewItemIndex = indexPath.row // 6
showViewController(previewQL, sender: nil) // 7
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = self.downloadsTable.dequeueReusableCellWithIdentifier("Download Cell") as? DownloadsTableCell {
cell.initCell(items[indexPath.row].name, detail: "", fileURL: items[indexPath.row].url)
return cell
}
return DownloadsTableCell()
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
// let fileManager = NSFileManager.defaultManager()
//
// // Delete 'hello.swift' file
//
// do {
// try fileManager.removeItemAtPath(String(items[indexPath.row].url))
// }
// catch let error as NSError {
// print("Ooops! Something went wrong: \(error)")
// }
items.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
override func viewDidAppear(animated: Bool) {
items.removeAll()
let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
// now lets get the directory contents (including folders)
do {
let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
// print(directoryContents)
for var file in directoryContents {
print(file.lastPathComponent)
print(file.absoluteURL)
// Save the data in the list as a tuple
self.items.append((file.lastPathComponent!, file.absoluteString))
}
} catch let error as NSError {
print(error.localizedDescription)
}
downloadsTable.reloadData()
}
// MARK: Preview
func numberOfPreviewItemsInPreviewController(controller: QLPreviewController) -> Int {
return items.count
}
func previewController(controller: QLPreviewController, previewItemAtIndex index: Int) -> QLPreviewItem {
return NSURL(string: items[index].url)!
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
//do something
super.viewWillAppear(true)
}
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.
}
*/
}
Looks like the view that your UISearchController is attached to gets removed from the view hierarchy. You can think of the UISearchController as being presented modally when you start searching, and the definesPresentationContext property indicates which UIViewController would be the one to present it (more on this).
One of the ways to fix this would be reconfiguring your storyboard so that each tab has its own UINavigationController (in case you need it for both):
Instead of (what I suspect you have now):
And if you want to dismiss UISearchController when the tab switches, add this override to the ViewController:
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
searchController.active = false
}

Passing an icon and name from TableviewController B to TableviewController A

I am trying to pass an icon and a name from tableview Controller B to view controller A via a delegate.
To put this simple, a user is presented with ViewController A: (Shown here)
ViewController A and source code
ViewController A source
//
// MasterTableViewController.swift
// Sample image
//
//
import UIKit
class MasterTableViewController: UITableViewController, IconselectedDelegate {
#IBOutlet weak var passedIconName: UILabel!
var tempname: String?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Master"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
}
func iconName(iconName: String) -> String {
self.tempname = iconName
self.passedIconName.text = "\(iconName)"
return tempname!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
So when when the user taps this cell, the user is then presented with another view controller (viewController B) that shows a list of icons. Here is the Screenshot and source code for this sample.
ViewController B
Here is the sample code for Viewcontroller B
ViewController B code
//
// IconTableViewController.swift
// Sample image
//
// Created by me on 4/18/16.
//
import UIKit
protocol IconselectedDelegate {
func iconName(iconName: String)-> String
}
class IconTableViewController: UITableViewController {
enum Icon: Int {
case Study
case Apple
var icon: UIImage {
switch self {
case.Study: return UIImage(named: "study")!
case.Apple: return UIImage(named: "apple")!
}
}
}
var icons = ["Study", "Apple"]
var delegate: IconselectedDelegate? = nil
var selectedIndex = 0
// holding vars
var image: UIImage?
var name: String?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Icon selection"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return icons.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell: UITableViewCell! = tableView.cellForRowAtIndexPath(indexPath)
if cell.accessoryType == UITableViewCellAccessoryType.None {
if indexPath.row == 0 {
self.name = icons[0]
} else if indexPath.row == 1 {
self.name = icons[1]
}
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
self.navigationController?.popToRootViewControllerAnimated(true)
}
selectedIndex = indexPath.row
tableView.reloadData()
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! IconTableViewCell
// Configure the cell...
cell.iconName.text = icons[indexPath.row]
if let iconIndex = Icon(rawValue: indexPath.row) {
cell.iconPreview.image = iconIndex.icon
}
return cell
}
override func viewWillDisappear(animated: Bool) {
super.viewWillAppear(true)
if name == nil {
delegate?.iconName("None")
} else {
delegate?.iconName(name!)
print("Delegate left with \(delegate?.iconName(name!))")
}
}
}
PROBLEM
I want to pass the selected icon back to the master view controller showing both the name and the icon image. (In master view controller, there is a UIImage object but you can't see it right next to the UILable saying 'select')
How can i achieve this? I used this similar code for accomplishing UIColor and it worked but it does not seem to work with images.
Would greatly help
Set values from your DestinationViewController back to your Primary (First) ViewController
1. Implement a protocol, for example create a file called protocol.swift.
protocol SetIconValueDelegate {
func didChoose(icon:Icon)
}
2. set the delegate on your second ViewController
class yourNextViewControllerClass {
var delegate:SetIconValueDelegate?
3. set the delegate when you load your secondViewController (with Icon Details)
if(segue.identifier == "yourIdentifierInStoryboard") {
var yourNextViewController = (segue.destinationViewController as yourNextViewControllerClass)
yourNextViewController.delegate = self
4. add Function to FirstViewController
func didChoose(icon:Icon) {
// set here whatever you want
}
5. call this function from your SecondViewController
delegate?.didChoose(icon) // this will send your "icon" object - run this from didSelectRowAtIndexPath
6. Set the delegate in your FirstViewController
class FirstViewController: UIViewController, setIconValueDelegate {
You can use delegate(protocol) methods to send back data to previous view controller.
IN CURRENT VC:
protocol MyProtocol: class
{
func sendArrayToPreviousVC(myArray:[AnyObject])
}
Make a var in your class.
weak var mDelegate:MyProtocol?
Now call the protocol method when you pop the view controller, with your "properties" array as parameter. (in your case from did select row pass what you want like icon or name)
mDelegate?.sendArrayToPreviousVC(properties)
IN PREVIOUS VC:
In your previous VC, set the mDelegate property to self, when you push the current VC.
currentVC.mDelegate = self
//PUSH VC
Now implement the protocol method in your previous VC.
func sendArrayToPreviousVC(myArray:[AnyObject]) {
//DO YOUR THING
}
This is the scenario that how can send data back in navigation stack. adjust according to your data and requirement.
You should use didselect row delegate method to pass data.
hope this will help :)

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