Can't pass variable into prepareForSegue in Swift? - ios

I'm trying to pass selectedName to VC #2 (BrandTableViewController). If I println(selectedName) in viewDidDisappear I get the value, however, the value is nil when it's in prepareForSegue? Can anyone see why?
import UIKit
import CoreData
class NameTableViewController: UITableViewController, UITableViewDelegate {
//Changes [String] to [NSManagedObject]
var people = [NSManagedObject]()
#IBOutlet var nameTableView: UITableView!
var selectedName: Person?
override func viewDidLoad() {
super.viewDidLoad()
title = "\"People\""
nameTableView.delegate = self
// 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()
// Retreive the managedObjectContext from AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
// Print it to the console
println(managedObjectContext)
}
// Mark: - Add Button Alert
#IBAction func addButton(sender: AnyObject) {
var alert = UIAlertController(title: "New name",
message: "Add a new name",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default) { (action: UIAlertAction!) -> Void in
let textField = alert.textFields![0] as! UITextField
self.saveName(textField.text)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
//function to save a name (code from: http://www.raywenderlich.com/85578/first-core-data-app-using-swift)
func saveName(name: String) {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let entity = NSEntityDescription.entityForName("Person",
inManagedObjectContext:
managedContext)
let person = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
//3
person.setValue(name, forKey: "name")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
//5
people.append(person)
}
// 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 people.count
}
private struct Storyboard {
static let CellReuseIdentifier = "Name"
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(Storyboard.CellReuseIdentifier, forIndexPath: indexPath) as! UITableViewCell
let person = people[indexPath.row]
cell.textLabel!.text = person.valueForKey("name") as? String
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = self.tableView.indexPathForSelectedRow()!.row
println("row \(row) was selected")
selectedName = people[indexPath.row] as? Person
println(selectedName)
// if let unWrappedSelectedName = selectedName {
// // println(unWrappedSelectedName)
// }
// else {
// println("no person was selected in didSelectRowAtIndexPath")
// }
}
// 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 {
let personToDelete = people[indexPath.row]
//abstract this into helper function later
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
managedContext.deleteObject(personToDelete)
self.fetchCoreData()
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
}
*/
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
fetchCoreData()
}
//Helper Function to Fetch Core Data
func fetchCoreData() {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"Person")
//3
var error: NSError?
let fetchedResults = managedContext.executeFetchRequest(fetchRequest,
error: &error) as? [NSManagedObject]
if let results = fetchedResults {
people = results
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let btvc = segue.destinationViewController as? BrandsTableTableViewController {
if let identifer = segue.identifier {
if identifer == "segueToBrands" {
btvc.selectedName = selectedName
println(selectedName)
}
}
}
else {
println("we have a segue problem")
}
}

The prepareForSegue: method is called before tableView:didSelectRowAtIndexPath: method.And I saw that you only assign selectedName in method didSelectRowAtIndexPath.So selectedName will always be nil in prepareForSegue.
You can assign selectedName in tableView:willSelectRowAtIndexPath:
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = self.tableView.indexPathForSelectedRow()!.row
println("row \(row) was selected")
selectedName = people[indexPath.row] as? Person
println(selectedName)
}

In your preprareForSegue() you can access the selected cell (or cells) as such:
override func prepareForSegue (segue: UIStoryboardSegue, sender: AnyObject?) {
switch segue.identifier ?? "" {
case "theSegue":
if let indexPath = tableView.indexPathForSelectedRow () {
// get what you need from the cell or the DataSource object
let controller = segue.destinationViewController as! PersonController
controller.person = people[indexPath.row]
}
// ...
}
}

Related

Swift - can't reload Data from TableView after add button action

I'm new to Swift and need your help.
I created a TableViewController with a custom cell.
Also I created a "add" Button in navigation bar to add a new value to my tableview.
Saving the values in Core Data and fetch them in viewWillAppear.
When pressing the add button a UIAlertController shows up which i had customized like i needed. I added a cancel action and a ok action but when i press the ok button from the alert the new value don't shows up in my tableview. I have to switch to an other viewcontroller that the tableview shows it.
I added groupsTableView.reloadData()on different points in my code but cant get it to work.
Hope someone can help me out!
Code from MasterViewController:
import UIKit
import CoreData
class MasterViewController: UITableViewController {
var groups: [Groups] = []
#IBOutlet weak var groupsTableView: UITableView!
var groupsTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
groupsTableView.delegate = self
groupsTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
// Core date initialization
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Groups> = Groups.fetchRequest()
do {
groups = try managedContext.fetch(fetchRequest)
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not fetch groups")
}
navigationItem.leftBarButtonItem = editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject))
navigationItem.rightBarButtonItem = addButton
}
// MARK: - add new Group
#objc func insertNewObject() {
let addButtonAlert = UIAlertController(title: "Neue Gruppe", message: "Füge eine neue Gruppe deiner Liste hinzu", preferredStyle: .alert)
addButtonAlert.addTextField { (UITextField) in
self.groupsTextField = UITextField
self.groupsTextField?.placeholder = "Name der Gruppe"
self.groupsTextField?.clearButtonMode = .whileEditing
}
let okAction = UIAlertAction(title: "Hinzufügen", style: .default, handler: addNewGroup)
let cancelAction = UIAlertAction(title: "Abbrechen", style: .cancel, handler: nil)
addButtonAlert.addAction(okAction)
addButtonAlert.addAction(cancelAction)
self.present(addButtonAlert, animated: true, completion: nil)
}
func addNewGroup(_:UIAlertAction) -> Void {
let group = Groups(groupId: UUID(), groupTitle: groupsTextField!.text ?? "")
do {
try group?.managedObjectContext?.save()
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not save group")
}
}
// MARK: - Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destination = segue.destination as? DetailViewController,
let selectedRow = self.groupsTableView.indexPathForSelectedRow?.row else {
return
}
destination.group = groups[selectedRow]
destination.title = groups[selectedRow].groupTitle
}
// MARK: - delete Group
func deleteGroup(at indexPath: IndexPath) {
let group = groups[indexPath.row]
guard let managedContext = group.managedObjectContext else {
return
}
managedContext.delete(group)
do {
try managedContext.save()
groups.remove(at: indexPath.row)
groupsTableView.deleteRows(at: [indexPath], with: .automatic)
} catch {
//TODO: error handling
print("Could not delete Group")
groupsTableView.reloadRows(at: [indexPath], with: .automatic)
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return groups.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = groupsTableView.dequeueReusableCell(withIdentifier: "GroupsTableViewCell", for: indexPath) as! GroupsTableViewCell
let object = groups[indexPath.row]
cell.groupTitleLabel?.text = object.groupTitle
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deleteGroup(at: indexPath)
}
}
}
Add group item to your groups array and after that reload your tableview as shown below:-
func addNewGroup(_:UIAlertAction) -> Void {
let group = Groups(groupId: UUID(), groupTitle: groupsTextField!.text ?? "")
do {
try group?.managedObjectContext?.save()
self.groups.append(group)
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not save group")
}
}

Edit the contents list of TableViewCell in Swift

I have a TableViewController with lists of data entry using CoreData. I also have ViewController with UITextView as linked by Segue to TableViewController. I have completed operations like add, save and delete on items.
Now I am working on edit by linking the selected TableViewCell to UITextView on next ViewController.I have created an action DONE on ViewController.I am able to pass data from selected Cell to TextView of next ViewController using Segue.
Now, I need to update the edited text on UITextView by clicking DONE button to back to Cells of TableViewController and also save data to CoreData. Plzz give the genuine advices and suggestions....I am new to Swift and I have enclosed my code here.
import UIKit
import CoreData
class ToDoTableViewController: UITableViewController {
var listItems = [NSManagedObject]()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.add, target: self , action: #selector(ToDoTableViewController.addItem))
}
func addItem(){
let alertController = UIAlertController(title: "To Do Tasks Lists!!!!", message: "Write Down...", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Confirm", style: UIAlertActionStyle.default, handler: ({
(_) in
if let field = alertController.textFields![0] as? UITextField {
self.saveItem(itemToSave: (field.text!))
self.tableView.reloadData()
}
}
))
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addTextField(configurationHandler: ({
(textField) in
textField.placeholder = "Type in Something!!!!"
}))
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
func saveItem(itemToSave : String){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: "ListEntity", in: managedContext)
let item = NSManagedObject(entity: entity!, insertInto: managedContext)
item.setValue(itemToSave, forKey: "item")
do {
try managedContext.save()
listItems.append(item)
}
catch {
print("Error")
}
}
override func viewWillAppear(_ animated: Bool) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "ListEntity")
do{
let results = try managedContext.fetch(fetchRequest)
listItems = results as! [NSManagedObject]
}
catch {
print("Error")
}
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let objectToDelete = listItems[indexPath.row]
listItems.remove(at: indexPath.row)
managedContext.delete(objectToDelete)
tableView.deleteRows(at: [indexPath], with: .fade)
do {
try managedContext.save()
}
catch {
print("Error")
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")! as UITableViewCell
let item = listItems[indexPath.row]
cell.textLabel?.text = item.value(forKey: "item") as! String?
cell.backgroundColor = UIColor.clear
return cell
}
func getIndexPathForSelectedCell() -> IndexPath?
{
var indexPath2:IndexPath?
if tableView.indexPathsForSelectedRows!.count > 0 {
indexPath2 = tableView.indexPathsForSelectedRows![0]
}
return indexPath2
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "detailView")
{
if let indexPath2 = getIndexPathForSelectedCell()
{
// here write code for move to next controller.
let vc = segue.destination as! TextEditViewController
//vc.FirstString = listItems[(indexPath2 as NSIndexPath).row] as String
let item = listItems[(indexPath2 as NSIndexPath).row]
vc.FirstString = (item.value(forKey: "item") as! String?)!
}
}
}
}
//TextEditViewController
import UIKit
import CoreData
class TextEditViewController: UIViewController {
#IBOutlet weak var textEdit: UITextView!
var FirstString = String()
override func viewDidLoad() {
super.viewDidLoad()
textEdit.text = FirstString
print(self.FirstString)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Pass your CoreData model reference to next screen:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "detailView")
{
if let indexPath2 = getIndexPathForSelectedCell()
{
// here write code for move to next controller.
let vc = segue.destination as! TextEditViewController
//vc.FirstString = listItems[(indexPath2 as NSIndexPath).row] as String
let item = listItems[(indexPath2 as NSIndexPath).row]
vc.FirstString = (item.value(forKey: "item") as! String?)!
vc.recentItem = item; //Like this. Create a recentItem refrence to your next controller of NSManagedObject or your custom core data modal.
}
}
}
When you are done with your editing in TextEditViewController:
recentItem.item = "String" //Your updated string
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
do {
try managedContext.save()
}
catch {
print("Error")
}
Hope this will work...!!

What i should change in my code to access all the contacts instead of just 1 contact with swift?

I have a really specific problem. I want to access and present to a table view the user's contact list. The problem is that when I run the code I access only one contact from the contact list. I'm trying to think what I should change but nothing so far. Given the code below what I need to change the achieve the result that I want? Here is the code:
import UIKit
import Contacts
import AddressBook
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var objects = [CNContact]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let addExisting = UIBarButtonItem(title: "Add Existing", style: .Plain, target: self, action: #selector(MasterViewController.addExistingContact))
self.navigationItem.leftBarButtonItem = addExisting
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MasterViewController.insertNewObject(_:)), name: "addNewContact", object: nil)
self.getContacts()
}
func getContacts() {
let store = CNContactStore()
if CNContactStore.authorizationStatusForEntityType(.Contacts) == .NotDetermined {
store.requestAccessForEntityType(.Contacts, completionHandler: { (authorized: Bool, error: NSError?) -> Void in
if authorized {
self.retrieveContactsWithStore(store)
}
})
} else if CNContactStore.authorizationStatusForEntityType(.Contacts) == .Authorized {
self.retrieveContactsWithStore(store)
}
}
func retrieveContactsWithStore(store: CNContactStore) {
do {
let groups = try store.groupsMatchingPredicate(nil)
let predicate = CNContact.predicateForContactsInGroupWithIdentifier(groups[0].identifier)
//let predicate = CNContact.predicateForContactsMatchingName("John")
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey]
let contacts = try store.unifiedContactsMatchingPredicate(predicate, keysToFetch: keysToFetch)
self.objects = contacts
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
} catch {
print(error)
}
}
func addExistingContact() {
}
override func viewWillAppear(animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertNewObject(sender: NSNotification) {
if let contact = sender.userInfo?["contactToAdd"] as? CNContact {
objects.insert(contact, atIndex: 0)
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 = objects[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.contactItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let contact = self.objects[indexPath.row]
let formatter = CNContactFormatter()
cell.textLabel?.text = formatter.stringFromContact(contact)
cell.detailTextLabel?.text = contact.emailAddresses.first?.value as? String
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 false
}
}
This is how I currently get a list of the user's contacts and store them in a CNContact array.
let request = CNContactFetchRequest(keysToFetch: [CNContactEmailAddressesKey, CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)])
var contacts = [CNContact]()
do {
try store.enumerateContactsWithFetchRequest(request) { contact, stop in
contacts.append(contact)
}
self.objects = contacts
NSOperationQueue.mainQueue().addOperationWithBlock({
self.tableView.reloadData()
})
} catch {
print(error)
}
I'm assuming your problem is with the line groupsMatchingPredicate(nil), where you don't pass in a predicate so it can't find any matches. Just a thought.

Segue not going on Table Cell click

I am having a problem with my TableCell Segue.
I have setup a Segue with the identifier ShowAssesment on the prototype cell to Show a navigation controller connected to a table view, but when i click a cell it just highlights it and nothing happens.
class ViewController: UIViewController, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var subjects = [NSManagedObject]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
}
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return subjects.count
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("Cell")
let check = subjects[indexPath.row]
cell!.textLabel!.text =
check.valueForKey("name") as? String
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addName(sender: AnyObject) {
let alert = UIAlertController(title: "New Subject", message: "Add a new Subject", preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default,
handler: { (action:UIAlertAction) -> Void in
let textField = alert.textFields!.first
self.saveName(textField!.text!)
self.tableView.reloadData()
})
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textField: UITextField) -> Void in
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
func saveName(name: String) {
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("Subjects",
inManagedObjectContext:managedContext)
let check = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
check.setValue(name, forKey: "name")
do {
try managedContext.save()
subjects.append(check)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Subjects")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
subjects = results as! [NSManagedObject]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle,forRowAtIndexPath indexPath: NSIndexPath) {
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "ShowAssesment") {
let indexPath = tableView.indexPathForCell((sender as? UITableViewCell)!)
let listVC = segue.destinationViewController as? AssesmentViewController
let subject = subjects[indexPath!.row]
listVC?.assesments = ["Death"]
}
}
}
I don't know if you have setup your segue properly and connect it to a button in cell or so but if you wan't to be on cell tap you need to implement didselectrow and perform segue from code like
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("ShowAssesment", sender: self);
}
Check to make sure you set it up correctly. You also might try something like
func tableView(tableView:UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
self.performSegueWithIdentifier("ShowAssesment", sender: tableView.cellForRowAtIndexPath(indexPath))
}

Swift filter UITableView with out search bar

I have a UITableView that I want to filter based on a selection from slide panel view controller. This is the function that gets the returned value form the panel.
func itemSelected(type: Item) {
self.selectedItem = Item.title
delegate?.collapseSidePanels?()
}
Table view code.
var myData: Array<AnyObject> = []
var selectedItem:Array<AnyObject> = []
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID: NSString = "Cell"
var Cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellID as String) as! UITableViewCell
var data: NSManagedObject = myData[indexPath.row] as! NSManagedObject
if tableView == selectedItem {
data = self.selectedItem[indexPath.row] as! NSManagedObject
} else
{
data = myData[indexPath.row] as! NSManagedObject
}
Cell.textLabel?.text = data.valueForKeyPath("itemname") as? String
var tt = data.valueForKeyPath("itemtype") as! String
Cell.detailTextLabel?.text = ("Item Type: \(tt)")
return Cell
}
I need to filter on the itemtype.
edit - Will not filter still so here is the full code for the tableViewController.
import UIKit
import CoreData
import Foundation
#objc
protocol tableViewControllerDelegate {
optional func toggleLeftPanel()
optional func toggleRightPanel()
optional func collapseSidePanels()
}
class tableViewController: UITableViewController, NSFetchedResultsControllerDelegate, SidePanelViewControllerDelegate {
var delegate: tableViewControllerDelegate?
var myData: Array<AnyObject> = []
var myFilteredData: Array<AnyObject> = []
#IBAction func leftTapped(sender: AnyObject) {
delegate?.toggleLeftPanel?()
}
// Use this to change table view to edit mode
// and to Change the title when clicked on.
// Make sure to have sender set as UIBarButtonItem
// or you can not change the title of the button.
var condition: Bool = true
#IBAction func buttonEdit(sender: UIBarButtonItem) {
if(condition == true) {
tableView.editing = true
sender.title = "Done"
condition = false
} else {
tableView.editing = false
sender.title = "Edit"
condition = true
}
}
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
// This is neeed when using panel view controller to show the bottom navbar.
self.navigationController?.setToolbarHidden(false, animated: true)
// ref app del
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
// Ref data
let context: NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "Products")
myData = context.executeFetchRequest(freq, error: nil)!
}
override func viewDidAppear(animated: Bool) {
}
// 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.
if (self.myFilteredData.count != 0) {
return self.myFilteredData.count
} else {
return self.myData.count
}
}
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: NSFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID: String = "Cell"
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellID as String) as! UITableViewCell
var data: NSManagedObject
if (self.myFilteredData.count != 0){
data = myFilteredData[indexPath.row] as! NSManagedObject
cell.textLabel?.text = data.valueForKeyPath("productname") as? String
var tt = data.valueForKeyPath("itemtype") as! String
cell.detailTextLabel?.text = ("Item J Type: \(tt)")
} else {
data = myData[indexPath.row] as! NSManagedObject
cell.textLabel?.text = data.valueForKeyPath("productname") as? String
var tt = data.valueForKeyPath("itemtype") as! String
cell.detailTextLabel?.text = ("Item Type: \(tt)")
}
return cell
}
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
let item: AnyObject = myData[sourceIndexPath.row]
myData.removeAtIndex(sourceIndexPath.row)
myData.insert(item, atIndex: destinationIndexPath.row)
}
// called when a row deletion action is confirmed
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// remove the deleted item from the model
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
context.deleteObject(myData[indexPath.row] as! NSManagedObject)
myData.removeAtIndex(indexPath.row)
context.save(nil)
// remove the deleted item from the `UITableView`
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showProduct"){
let selectedIndexPath:NSIndexPath = self.tableView.indexPathForSelectedRow()!
let genView:genViewController = segue.destinationViewController as! genViewController
genView.row = selectedIndexPath.row
}
else if (segue.identifier == "addProduct"){
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func itemSelected(item: Type) {
var selectedType = item.title
delegate?.collapseSidePanels?()
for (key, value) in enumerate(self.myData) {
if (value.valueForKeyPath("itemtype") !== "selectedType") {
self.myFilteredData.append(value)
dump(myFilteredData)
} else {
// do nothing with it
}
}
tableView.reloadData()
}
}
Depending on however you want the data filtered, you could loop through myData in itemSelected(), find the elements that you want in your filtered list and save them in a new array (myFilteredData).
var myFilteredData: Array<AnyObject> = []
func itemSelected(type: Item) {
self.selectedItem = Item.title
delegate?.collapseSidePanels?()
for (key, value) in enumerate(self.myData) {
if (value.valueForKeyPath("itemtype") == "yourCondition") {
self.myFilteredData.append(value)
} else {
// do nothing with it
}
}
tableView.reloadData() // use tableView.reloadSections with rowAnimation for better effect.
}
You would then reload the tableview with tableView.reloadSections(_ sections: NSIndexSet,
withRowAnimation animation: UITableViewRowAnimation), which will trigger the cellForRowAtIndexPath function. Here, you would need to decide if you want to use myData or myFilteredData for the cell's labels.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
...
var data:NSManagedObject
if (self.myFilteredData.count != 0) {
data = myFilteredData[indexPath.row] as! NSManagedObject
} else {
data = myData[indexPath.row] as! NSManagedObject
}
...
}
Also, don't forget to modify the numberOfRowsInSection function to return the size of the array you are populating the tableView with.
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.myFilteredData.count != 0) {
return self.myFilteredData.count
} else {
return self.myData.count
}
}

Resources