Segue not working in Swift - ios

I'm trying to pass a certain part of an array to another view controller based on which tableview cell you click on. So when I click on the third cell for example, it'll send the array data from the third cell to the next screen. This data is an array called "todos". When I try to receive the data in the next screen, there is no data.
Code:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditTodo" {
print("it is")
var vc = segue.destination as! ViewController
// var indexPath = tableView.indexPathForCell(sender as UITableViewCell)
var indexPath = tableView.indexPathForSelectedRow
if let index = indexPath {
vc.todo = todos[index.row]
}
}
}
I'm not sure if it's being called at all, or what. The identifier is correct, and I'm not sure what else to do. (When I run it, the print function is not called, but I'm not even sure if it's supposed to be).
Here is the whole page of code from the 'sending data' page with the table:
import UIKit
var todos: [TodoModel] = []
var filteredTodos: [TodoModel] = []
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
print("i think it worked...")
let defaults = UserDefaults.standard
if todos.count > 0 {
// Save what we have
let data = NSKeyedArchiver.archivedData(withRootObject: todos)
defaults.set(data, forKey: "TDDATA")
defaults.synchronize()
print("saved \(todos.count)")
} else if let storedTodoData = defaults.data(forKey: "TDDATA"),
let storedTodos = NSKeyedUnarchiver.unarchiveObject(with: storedTodoData) as? [TodoModel] {
// There was stored data! Use it!
todos = storedTodos
print("Used \(todos.count) stored todos")
tableView.reloadData()
self.tableView.tableFooterView = UIView()
}
//print([todos.first])
print("Here?: \(todos.first?.title)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override var prefersStatusBarHidden: Bool {
return true
}
/*
// 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?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == searchDisplayController?.searchResultsTableView {
return filteredTodos.count
}
else {
return todos.count
}
}
// Display the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Must use 'self' here because searchResultsTableView needs to reuse the same cell in self.tableView
let cell = self.tableView.dequeueReusableCell(withIdentifier: "todoCell")! as UITableViewCell
var todo : TodoModel
if tableView == searchDisplayController?.searchResultsTableView {
todo = filteredTodos[indexPath.row] as TodoModel
}
else {
todo = todos[indexPath.row] as TodoModel
}
//var image = cell.viewWithTag(101) as! UIImageView
var title = cell.viewWithTag(102) as! UILabel
var date = cell.viewWithTag(103) as! UILabel
//image.image = todo.image
// image = UIImageView(image: newImage)
// if image.image == nil{
// print("nilish")
// image = UIImageView(image: UIImage(named: "EmptyProfile.png"))
// }
// image.image = todo.image
// if image.image == nil{
// print("pic is nil")
// image.image = UIImage(named: "CopyEmptyProfilePic.jpg")
// }
title.text = todo.title
date.text = "\(NSDate())"
let locale = NSLocale.current
let dateFormat = DateFormatter.dateFormat(fromTemplate: "yyyy-MM-dd", options:0, locale:locale)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateFormat
return cell
}
// MARK - UITableViewDelegate
// Delete the cell
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
todos.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath as IndexPath], with: UITableViewRowAnimation.automatic)
let defaults = UserDefaults.standard
if todos.count >= 0 {
// Save what we have
let data = NSKeyedArchiver.archivedData(withRootObject: todos)
defaults.set(data, forKey: "TDDATA")
defaults.synchronize()
print("saved \(todos.count)")
} else if let storedTodoData = defaults.data(forKey: "TDDATA"),
let storedTodos = NSKeyedUnarchiver.unarchiveObject(with: storedTodoData) as? [TodoModel] {
// There was stored data! Use it!
todos = storedTodos
print("Used \(todos.count) stored todos")
}
tableView.reloadData()
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80
}
// Edit mode
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: true)
}
// Move the cell
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return self.isEditing
}
// func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
// let todo = todos.removeAtIndex(sourceIndexPath.row)
//todos.insert(todo, atIndex: destinationIndexPath.row)
// }
// MARK - UISearchDisplayDelegate
// Search the Cell
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String?) -> Bool {
//filteredTodos = todos.filter({( todo: TodoModel) -> Bool in
// let stringMatch = todo.title.rangeOfString(searchString)
// return stringMatch != nil
//})
// Same as below
filteredTodos = todos.filter(){$0.title.range(of: searchString!)
!= nil}
return true
}
// MARK - Storyboard stuff
// Unwind
#IBAction func close(segue: UIStoryboardSegue) {
print("closed!")
tableView.reloadData()
}
// Segue
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditTodo" {
print("it is")
var vc = segue.destination as! ViewController
// var indexPath = tableView.indexPathForCell(sender as UITableViewCell)
var indexPath = tableView.indexPathForSelectedRow
if let index = indexPath {
vc.todo = todos[index.row]
}
}
}
}
How I am receiving the data in viewDidLoad of receiving screen:
nameOfDocTF.delegate = self
nameOfDocTF.text = todo?.title
outputTextView.attributedText = todo?.desc
print(todo?.title)
//prints "nil"

As I suspected you´re missing the didSelectRowAt function which will be called when you click on a cell and from there you need to call your prepareForSegue. Implement the following function and try:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "EditTodo", sender: indexPath.row)
}
And then replace your prepareForSegue function with the following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EditTodo" {
let vc = segue.destination as! ViewController
if let index = sender as? Int {
vc.todo = todos[index]
}
}
}

Related

How to connect to tableview containers?

I am a beginner to Xcode and Swift and I am currently creating an application where the user adds a person on the application and after that it right the amount of money they owe that person or that person owes him/her.
Note: I have used core data to store all the value
I have ViewController called PeopleTableViewController where the user adds the name of the person they owe. Then I have PersonDetailTableViewController which shows the list of details the user owes that particular person the selected in PeopleTableViewController. The problem I am facing is that if I add three people in PeopleTableViewController and when I select any one of the people then I am directed to same tableview in PersonDetailTableViewController but I want different tableviews for different person the user selects in PeopleTableViewController.
PersonDetailTableViewController:
import UIKit
class PersonDetailTableViewController: UITableViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var totalLabel: UILabel?
var person: People?
var owe: Owe?
#IBOutlet var personTable: UITableView!
var dataInfo: [Owe] = []
var selectedObject: [Owe] = []
var balanceAmount = "Balance: "
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataInfo.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = personTable
.dequeueReusableCell(withIdentifier: "detailsCell", for: indexPath)
cell.textLabel?.text = dataInfo[indexPath.row].name
cell.detailTextLabel?.text = "₹ \(dataInfo[indexPath.row].amount)"
// if dataInfo[indexPath.row].amount < 0 {
// cell.detailTextLabel?.textColor = UIColor.red
// } else {
// cell.detailTextLabel?.textColor = UIColor.green
// }
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedObject = [dataInfo[indexPath.row]]
performSegue(withIdentifier: "addOweDetails", sender: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
personTable.dataSource = self
addTotalToNav()
print(dataInfo as Any)
}
// MARK: - Table view data source
func addTotalToNav() -> Void {
if let navigationBar = self.navigationController?.navigationBar {
let totalFrame = CGRect(x: 10, y: 0, width: navigationBar.frame.width/2, height: navigationBar.frame.height)
totalLabel = UILabel(frame: totalFrame)
totalLabel?.text = balanceAmount
totalLabel?.tag = 1
totalLabel?.font = UIFont.boldSystemFont(ofSize: 14)
totalLabel?.textColor = UIColor.red
// navigationBar.large = totalLabel?.text
self.title = totalLabel?.text
}
}
func getData() -> Void {
do{
dataInfo = try context.fetch(Owe.fetchRequest())
var total:Double = 0.00
for i in 0 ..< dataInfo.count {
total += dataInfo[i].amount as! Double
}
balanceAmount = "Balance: ₹" + (NSString(format: "%.2f", total as CVarArg) as String)
}
catch{
print("Fetching Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
personTable.reloadData()
if (self.navigationController?.navigationBar.viewWithTag(1)?.isHidden == true){
self.navigationController?.navigationBar.viewWithTag(1)?.removeFromSuperview()
addTotalToNav()
}
}
}
PeopleTableViewController:
import UIKit
import CoreData
class PeopleTableViewController: UITableViewController {
#IBOutlet weak var peopleTableView: UITableView!
var people: [People] = []
override func viewDidLoad() {
super.viewDidLoad()
peopleTableView.separatorStyle = .none
// 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
}
//ViewWillAppear allows us to fetch all the data in the backend and help us display to the user
override func viewWillAppear(_ animated: Bool) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<People> = People.fetchRequest()
do {
people = try managedContext.fetch(fetchRequest)
peopleTableView.reloadData()
} catch {
print("Could not fetch")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
}
//Following function is called right before the user segues from one viewcontroller to another viewcontroller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destination = segue.destination as? PersonDetailTableViewController,
let selectedRow = self.peopleTableView.indexPathForSelectedRow?.row else {
return
}
destination.person = people[selectedRow]
// destination.owe = people[selectedRow]
}
func deletePerson(at indexPath: IndexPath) {
let person = people[indexPath.row]
guard let managedContext = person.managedObjectContext else {
return
}
managedContext.delete(person)
do {
try managedContext.save()
people.remove(at: indexPath.row)
peopleTableView.deleteRows(at: [indexPath], with: .automatic)
} catch {
print("Could not delete")
peopleTableView.reloadRows(at: [indexPath], with: .automatic)
}
}
}
extension PeopleTableViewController{
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = peopleTableView.dequeueReusableCell(withIdentifier: "peopleCell", for: indexPath)
let person = people[indexPath.row]
cell.textLabel?.text = person.title
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deletePerson(at: indexPath)
}
}
}
The following images shows what I exactly require:
PeopleTableViewController
PeopleTableViewController
On clicking Mike I get following:
PersonDetailTableViewController
On clicking John I get following:
PersonDetailTableViewController
I want that the records for Mike and John should be different that is on PersonDetailTableViewController.
You can try (Both in PeopleTableViewController) , create a segue named shoePersonDetails from PeopleTableViewController to PersonDetailTableViewController
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let person = people[indexPath.row]
performSegue(withIdentifier: "shoePersonDetails", sender: person)
tableView.deselectRow(at: indexPath, animated: true)
}
//
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! PersonDetailTableViewController
vc.dataInfo = sender as! People
}

How to perform a different segue when in Edit mode (in UITableView)?

I am creating a simple iPhone app using UITableView. I am using the default MasterDetail application template. Right now (in Edit mode) when I press any of the table cells nothing happens. However, when I am in normal mode the detail segue is initiated. How to override the Edit mode so that I initiate a custom segue to go to a different UIViewController.
P.S.: I still want to preserve the inherit delete functionality.
This is my code in my MasterViewController:
class MasterViewController: UITableViewController {
let kFileName: String = "/resolutionData.plist"
var resolutions = [Dictionary<String,String>]()
var achievedResolutions = [Dictionary<String,String>]()
// TO DO create a class to get this array
let iconArray = ["Fish","Fly","Heart","HelpingHand","Melon","Star","Tentacles","Volunteering"]
override func awakeFromNib() {
super.awakeFromNib()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem()
let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:")
self.navigationItem.rightBarButtonItem = addButton
//extract the path
NSLog(dataFilePath())
/**
* Check where is the sandbox of the application
* and if there is read from the data file and story it to "objects" array
*/
if NSFileManager.defaultManager().fileExistsAtPath(dataFilePath()){
var temp = NSArray(contentsOfFile: dataFilePath()) as! [Dictionary<String,String>]
for res in temp{
if res["isAchieved"] == "Y"{
achievedResolutions.append(res)
}else{
resolutions.append(res)
}
}
//... if there is not - create it
} else {
let data = [["name":"Resolution name test","startingDate":"24-11-15","achievingDate":"01-01-2016","icon":iconArray[0],"isAchieved":"N"] as NSDictionary] as NSArray
//if the file does not exist...
if !NSFileManager.defaultManager().fileExistsAtPath(dataFilePath()){
//... create it
NSFileManager.defaultManager().createFileAtPath(dataFilePath(), contents: nil, attributes: nil)
}
//write to it
data.writeToFile(dataFilePath(), atomically: true)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertNewObject(sender: AnyObject) {
performSegueWithIdentifier("editDetails", sender: sender)
}
func saveDateToFile(){
let data = resolutions as NSArray
data.writeToFile(dataFilePath(), atomically: true)
}
func notifyTableViewForNewInsertion(){
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let object = resolutions[indexPath.row] as Dictionary
(segue.destinationViewController as! DetailViewController).detailItem = object
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Active"
}else{
return "Achieved"
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return resolutions.count
}else{
// TODO replace that with an actual array count
return achievedResolutions.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
if indexPath.section == 0{
let object: AnyObject? = resolutions[indexPath.row] ["name"]
cell.textLabel!.text = object as? String
cell.detailTextLabel!.text = resolutions[indexPath.row]["achievingDate"]
cell.imageView!.image = UIImage(named: resolutions[indexPath.row]["icon"]!)
} else {
let object: AnyObject? = achievedResolutions[indexPath.row] ["name"]
cell.textLabel!.text = object as? String
cell.detailTextLabel!.text = resolutions[indexPath.row]["achievingDate"]
cell.imageView!.image = UIImage(named: resolutions[indexPath.row]["icon"]!)
}
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
resolutions.removeAtIndex(indexPath.row)
saveDateToFile()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
func dataFilePath() -> String{
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
//get the first path and convert it to str
let docDicrectyory: String = paths[0] as! String
return "\(docDicrectyory)\(kFileName)"
}
}
Instead of performing your segue directly from the storyboard, add a UITableViewDelegate method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView.editing {
performSegueWithIdentifier("id_Segue_Editing_VC", sender: tableView.cellForRowAtIndexPath(indexPath))
} else {
performSegueWithIdentifier("id_Segue_Standard_VC", sender: tableView.cellForRowAtIndexPath(indexPath))
}
}
Set the sender to the selected cell -- this matches the default UIKit behavior.
Then in your prepareForSegue method you can add custom value to your view controllers according to the segue identifier.
Override willBeginEditingRowAtIndexPath: function. this willbe call before start editing. there you can initialize a global variable.
#property(nonatomic, String) BOOL editing
and in the
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (editing) {
if([[segue identifier] isEqualToString:#"identifierOne"]){
}else if([[segue identifier] isEqualToString:#"identifierTwo"]){
}
}
}
There is a table view property for that:
self.tableView.allowsSelectionDuringEditing = YES;

Data not being transferred between view controllers Swift

When a EventTableViewController proceeds to UserEventViewController or EventViewController the data is not transferred as the labels etc. are not updated to the transferred information. I have tried fix it but it still doesn't work. Please Help.
Any help would be great thanks.
Link to project:
https://www.dropbox.com/s/1d4d8opuxzpcuk4/TicketekApp.zip?dl=0
Code:
// EventTableViewController.swift
import UIKit
class EventTableViewController: UITableViewController {
// MARK: Properties
var events = [Event]()
var isAdmin = true
override func viewDidLoad() {
super.viewDidLoad()
// Use the edit button item provided by the table view controller.
navigationItem.leftBarButtonItem = editButtonItem()
// Load any saved events, otherwise load sample data.
if let savedEvents = loadEvents() {
events += savedEvents
} else {
// Load the sample data.
loadSampleEvents()
}
}
func loadSampleEvents() {
let photo1 = UIImage(named: "event1")!
let event1 = Event(name: "ACDC", photo: photo1, rating: 4, price: 500.0, eventDescription: "Album", album: "Album1")!
let photo2 = UIImage(named: "event2")!
let event2 = Event(name: "Cold Play", photo: photo2, rating: 5, price: 500.0, eventDescription: "Album", album: "Album1")!
let photo3 = UIImage(named: "event3")!
let event3 = Event(name: "One Direction", photo: photo3, rating: 3, price: 500.0, eventDescription: "Album", album: "Album1")!
events += [event1, event2, event3]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return events.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "EventTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! EventTableViewCell
// Fetches the appropriate event for the data source layout.
let event = events[indexPath.row]
cell.nameLabel.text = event.name
cell.photoImageView.image = event.photo
cell.ratingControl.rating = event.rating
cell.priceLabel.text = event.album
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let index = self.tableView.indexPathForSelectedRow?.row
//use the index to know which cell you selected
//check for your condition here something like
if isAdmin {
performSegueWithIdentifier("eventViewControllerSegue", sender: self)
} else {
performSegueWithIdentifier("userEventTableViewControllerSegue", sender: self)
}
}
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want item to be editable.
return true
}
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
events.removeAtIndex(indexPath.row)
saveEvents()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create new instance of class, add to the array, and add a new row to the table
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "eventViewControllerSegue" {
let eventDetailViewController = segue.destinationViewController as! EventViewController
// Get the cell that generated this segue.
if let selectedEventCell = sender as? EventTableViewCell {
let indexPath = tableView.indexPathForCell(selectedEventCell)!
let selectedEvent = events[indexPath.row]
eventDetailViewController.event = selectedEvent
}
} else if segue.identifier == "userEventTableViewControllerSegue" {
let eventDetailViewController = segue.destinationViewController as! UserEventViewController
// Get the cell that generated this segue.
if let selectedEventCell = sender as? EventTableViewCell {
let indexPath = tableView.indexPathForCell(selectedEventCell)!
let selectedEvent = events[indexPath.row]
eventDetailViewController.event = selectedEvent
}
}
else if segue.identifier == "AddItem" {
print("Adding new event.")
}
}
#IBAction func unwindToMealList(sender: UIStoryboardSegue) {
if let sourceViewController = sender.sourceViewController as? EventViewController, event = sourceViewController.event {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing event.
events[selectedIndexPath.row] = event
tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)
} else {
// Add a new event.
let newIndexPath = NSIndexPath(forRow: events.count, inSection: 0)
events.append(event)
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
}
// Save the events.
saveEvents()
}
}
// MARK: NSCoding
func saveEvents() {
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(events, toFile: Event.ArchiveURL.path!)
if !isSuccessfulSave {
print("Failed to save events...")
}
}
func loadEvents() -> [Event]? {
return NSKeyedUnarchiver.unarchiveObjectWithFile(Event.ArchiveURL.path!) as? [Event]
}
}
Shripada's answer is correct, no doubt. But, I would like to explain why your code ain't working.
You are calling performSegueWithIdentifier("eventViewControllerSegue", sender: self) from tableView:didSelectRowAtIndexPath method. Just note here that sender: self which is the ViewController and not the tableCell. Now, when this fires prepareForSegue, you are trying to access the selected cell using let selectedEventCell = sender as? EventTableViewCell . But, the sender is not the EventTableCell. Thats why you get a nil value and your if condition fails.
A simple fix would be to get the selected tableViewCell using tableView.indexPathForSelectedRow! in prepareForSegue and pass the appropriate data to destinationViewController.
let eventDetailViewController = segue.destinationViewController as! EventViewController
// Get the indexPath of selected cell
let indexPath = self.tableView.indexPathForSelectedRow!
let selectedEvent = events[indexPath.row]
eventDetailViewController.event = selectedEvent
You typically want to find the event related to the row selected. So, you will need to record which row is selected. Introduce a variable called as:
var currentlySelectedIndex = 0
to your EventTableViewController
Then change the implementation of didSelectRow delegate method in the same class to-
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//Record the row selected
currentlySelectedIndex = indexPath.row
//check for your condition here something like
if isAdmin {
performSegueWithIdentifier("eventViewControllerSegue", sender: self)
} else {
performSegueWithIdentifier("userEventTableViewControllerSegue", sender: self)
}
}
And thirdly, you will need to utilise this selected row index to fetch right event object:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "eventViewControllerSegue" {
let eventDetailViewController = segue.destinationViewController as! EventViewController
//Get the associated event
eventDetailViewController.event = events[currentlySelectedIndex]
} else if segue.identifier == "userEventTableViewControllerSegue" {
let eventDetailViewController = segue.destinationViewController as! UserEventViewController
//Get the associated event
eventDetailViewController.event = events[currentlySelectedIndex]
}
else if segue.identifier == "AddItem" {
print("Adding new event.")
}
}
This will resolve your issues.

Proceed to different view controllers based on boolean value

When a table cell is selected, I am trying to proceed to a view controller if the value of a boolean is true, else (if it is false), proceed to a different view controller. Any help would be great!
(The boolean is isAdmin and if true proceed to eventViewController, else proceed to UserEventTableViewController)
link to project:
https://www.dropbox.com/s/1d4d8opuxzpcuk4/TicketekApp.zip?dl=0
Code:
import UIKit
class EventTableViewController: UITableViewController {
// MARK: Properties
var events = [Event]()
var isAdmin = false
override func viewDidLoad() {
super.viewDidLoad()
// Use the edit button item provided by the table view controller.
navigationItem.leftBarButtonItem = editButtonItem()
// Load any saved events, otherwise load sample data.
if let savedEvents = loadEvents() {
events += savedEvents
} else {
// Load the sample data.
loadSampleEvents()
}
}
func loadSampleEvents() {
let photo1 = UIImage(named: "event1")!
let event1 = Event(name: "ACDC", photo: photo1, rating: 4, price: 500.0, eventDescription: "Album", album: "Album1")!
let photo2 = UIImage(named: "event2")!
let event2 = Event(name: "Cold Play", photo: photo2, rating: 5, price: 500.0, eventDescription: "Album", album: "Album1")!
let photo3 = UIImage(named: "event3")!
let event3 = Event(name: "One Direction", photo: photo3, rating: 3, price: 500.0, eventDescription: "Album", album: "Album1")!
events += [event1, event2, event3]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return events.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "EventTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! EventTableViewCell
// Fetches the appropriate event for the data source layout.
let event = events[indexPath.row]
cell.nameLabel.text = event.name
cell.photoImageView.image = event.photo
cell.ratingControl.rating = event.rating
cell.priceLabel.text = event.album
return cell
}
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want item to be editable.
return true
}
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
events.removeAtIndex(indexPath.row)
saveEvents()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create new instance of class, add to the array, and add a new row to the table
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowDetail" {
let eventDetailViewController = segue.destinationViewController as! EventViewController
// Get the cell that generated this segue.
if let selectedEventCell = sender as? EventTableViewCell {
let indexPath = tableView.indexPathForCell(selectedEventCell)!
let selectedEvent = events[indexPath.row]
eventDetailViewController.event = selectedEvent
print(selectedEventCell)
}
}
else if segue.identifier == "AddItem" {
print("Adding new event.")
}
}
#IBAction func unwindToMealList(sender: UIStoryboardSegue) {
if let sourceViewController = sender.sourceViewController as? EventViewController, event = sourceViewController.event {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing event.
events[selectedIndexPath.row] = event
tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)
} else {
// Add a new event.
let newIndexPath = NSIndexPath(forRow: events.count, inSection: 0)
events.append(event)
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
}
// Save the events.
saveEvents()
}
}
// MARK: NSCoding
func saveEvents() {
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(events, toFile: Event.ArchiveURL.path!)
if !isSuccessfulSave {
print("Failed to save events...")
}
}
func loadEvents() -> [Event]? {
return NSKeyedUnarchiver.unarchiveObjectWithFile(Event.ArchiveURL.path!) as? [Event]
}
}
You have to implement the tableView delegate method didSelectRowAtIndexPath.
example as follows:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let index = self.tableView.indexPathForSelectedRow?.row
//use the index to know which cell you selected
//check for your condition here something like
if isAdmin {
performSegueWithIdentifier("eventViewControllerSegue", sender: self)
} else {
performSegueWithIdentifier("userEventTableViewControllerSegue", sender: self)
}
}
note the following:
In your story board, draw segues to the different view controllers and assign the segue ID respectively.
In your code you are not changing the value of isAdmin boolean. Check that too.
Regards.
Image on how to segue from ViewController for your reference
I believe you can accomplish what you are seeking by using tableView:didSelectRowAtIndexPath: from the UITableViewDelegate protocol.
Add this to your view controller
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
and handle your logic within that function.
When you are ready to go to the next view controller, use
performSegueWithIdentifier(identifier: String, sender: AnyObject?)
Here is an example:
if isAdmin {
performSegueWithIdentifier(identifier: "segueToAdminView", sender: self)
} else {
performSegueWithIdentifier(identifier: "segueToUserEventView", sender: self)
}

I am trying to fetch image from a URL and make it as a thumbnail for my contacts in my application

I can fetch the image from a url and able to display the image in a UIImageView in my DetailViewController. I would like to display the same image from this URL as a thumbnail in my tableviewcell.
My viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.UrlField.text = contact.Imageurl
let urlString = UrlField.text
loadImageView(urlString)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
let urlString = UrlField.text
loadImageView(urlString)
textField.resignFirstResponder()
return true
}
In this function I try to fetch the image from the URL
func loadImageView(url : String){
self.contact.Imageurl = url
self.contact.data = nil
let DatatoImage: (NSData?) -> Void = {
if let d = $0 {
let image = UIImage(data: d)
self.imageView.image = image
}else{
self.imageView.image = nil
}
}
if let d = contact.data {
DatatoImage(d)
} else {
contact.loadImage(DatatoImage)
}
}
In my cellForRowAtIndexPath I managed to load an image that I have hardcoded in my folder and named it as "images1.jpeg"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
MainViewController
import UIKit
class MasterTableViewController: UITableViewController, ContactDetailTableViewControllerDelegate {
var contacts: [ContactListEntry] = []
var currentContact: ContactListEntry!
var detailObject: ContactDetailTableViewController!
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()
}
#IBAction func addContact(sender: UIBarButtonItem) {
currentContact = ContactListEntry(firstName: "", lastName: "", address: "", Imageurl: "")
contacts.append(currentContact)
performSegueWithIdentifier("showDetail", sender: self)
}
/* override func viewWillAppear(animated: Bool) {
if self.currentContact == nil || self.currentContact.isEmpty()
{
if count(contacts) > 0
{
contacts.removeLast()
}
}
tableView.reloadData()
}*/
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 Potentially incomplete method implementation.
// Return the number of sections.
return 1
}*/
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return contacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("contactcell", forIndexPath: indexPath) as! UITableViewCell
let contact = contacts[indexPath.row]
cell.textLabel?.text = "\(contact.firstName) \(contact.lastName)"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
let url = NSURL(string: "<# place your URL here #>")
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
*/
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// 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.
}
*/
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let cell = sender as? UITableViewCell
{
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
if (segue.identifier == "showDetail")
{
if let dvc = segue.destinationViewController as? ContactDetailTableViewController{
let indexPath = tableView.indexPathForCell(cell)!
currentContact = contacts[indexPath.row]
dvc.contact = currentContact
}}}
if let dvc = segue.destinationViewController as? ContactDetailTableViewController
{
dvc.contact = currentContact
dvc.delegate = self
}
}
func masterViewController(dvc: ContactDetailTableViewController, didUpdate contact: Person)
{
dvc.contact = currentContact
dvc.delegate = self
dvc.dismissViewControllerAnimated(true, completion: nil)
navigationController?.popToViewController(self, animated: true)
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
}
/* Create our configuration first In view did load */
let configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15.0
configuration.URLCache=NSURLCache(memoryCapacity: 4*1024*1024, diskCapacity: 20*1024*1024, diskPath: "CustomName"))
configuration.requestCachePolicy=NSURLRequestUseProtocolCachePolicy;
/* Now create our session which will allow us to create the tasks */
var session: NSURLSession!
session = NSURLSession(configuration: configuration,
delegate: self,
delegateQueue: nil)
/* Now attempt to download the contents of the URL in tableView cellForRowAtIndexpath */
let url = NSURL(string: "<# place your URL here #>")
task=session.dataTaskWithRequest(url!, completionHandler: { (NSData!, NSURLResponse!, NSError!) -> Void in
cell.imageView.image=UIImage(data: NSData))
})
task.start()
You can also set the cache,so that next tym when the request is fired then it is called from cache

Resources