Cannot assign to property: 'itemArray' is a get-only property - arrays

I am currently trying to implement a simple search function using UISearchBar and Core Data I am getting an error within this function "Cannot assign to property: "ItemArray" is a get-only property" If anyone can help with the error and also suggest another simple way to implement the search that would be really helpful.
func loadItems(with request: NSFetchRequest<Item>) {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request)
} catch {
print("Error fetching data from context")
}
tableView.reloadData()
}
}
Here is the whole file:
import UIKit
import CoreData
class TodoListViewController: UITableViewController {
var itemArray: [Item] { return Array(self.category.items!) as! [Item] }
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var category: Category!
override func viewDidLoad() {
super.viewDidLoad()
print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask))
}
#IBOutlet weak var todoTableView: UITableView!
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoItemCell", for: indexPath)
let item = itemArray[indexPath.row]
cell.textLabel?.text = item.title
cell.accessoryType = item.done ? .checkmark : .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//print(itemArray[indexPath.row])
itemArray[indexPath.row].done = !itemArray[indexPath.row].done
saveItems()
tableView.deselectRow(at: indexPath, animated: true)
}
#IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
var textField = UITextField()
let alert = UIAlertController(title: "Add New Todoey Item", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "Add Item", style: .default) { [weak self] (action) in
guard let self = self else { return }
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newItem = Item(context: self.context)
newItem.title = textField.text!
self.category.addToItems(newItem)
self.saveItems()
}
alert.addTextField { (alertTextField) in
alertTextField.placeholder = "Create new item"
textField = alertTextField
print(alertTextField.text)
}
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
func saveItems() {
do {
try context.save()
} catch {
print("Error saving context")
}
self.tableView.reloadData()
}
func loadItems(with request: NSFetchRequest<Item>) {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request)
} catch {
print("Error fetching data from context")
}
tableView.reloadData()
}
}
extension TodoListViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let request : NSFetchRequest<Item> = Item.fetchRequest()
request.predicate = NSPredicate(format: "title CONTAINS[cd] %#", searchBar.text!)
request.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
loadItems(with: request)
tableView.reloadData()
}

itemArray is declared as read-only property, that's exactly what the error says.
A solution is to declare the property as empty array
var itemArray = [Item]()
and call loadItems in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
loadItems()
print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask))
}
The parameter in loadItems is pointless, omit it.
func loadItems() { ... }
If you want to fetch the items for a specific Category add an appropriate NSPredicate in loadItems

Related

How do you save new index location in persistentcontainer?

I have a tableview where I have added the ability to move the location of rows. I am able to use the "swapAt" function to update my array and it works fine. The problem is that when I close and re-open the app, the rows continue to show in their old IndexPath. How can I also update the index location in the PersistentContainer so that when I open the app, it is updated with the new IndexPath?
I tried calling the save method of the context but it does not work.
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var toDoList = [Item] ()
var count: Int {
toDoList.count
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addItem))
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editItem))
title = "Todo"
loadItem()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return toDoList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
cell.textLabel?.text = toDoList [indexPath.row].title
if toDoList[indexPath.row].checkmark == true {
cell.accessoryType = .checkmark }
else {
cell.accessoryType = .none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if toDoList[indexPath.row].checkmark == false {
toDoList[indexPath.row].checkmark = true } else {
toDoList[indexPath.row].checkmark = false
}
tableView.reloadData()
saveItem()
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
toDoList.swapAt(sourceIndexPath.row, destinationIndexPath.row)
saveItem()
}
#objc func addItem () {
let ac = UIAlertController(title: "Add new category", message: nil, preferredStyle: .alert)
var textField = UITextField()
let submitAction = UIAlertAction(title: "Add", style: .default) { (action) in
let newItem = Item(context: self.context)
newItem.title = textField.text
newItem.checkmark = false
newItem.order = Int64(self.count)
self.toDoList.append(newItem)
self.saveItem()
}
ac.addTextField { (alertTextField) in
alertTextField.placeholder = "Create new item"
textField = alertTextField
}
ac.addAction(submitAction)
present(ac, animated: true, completion: nil)
}
func saveItem () {
do {
try context.save()
} catch {
print("This is the \(error)")
}
self.tableView.reloadData()
}
func loadItem () {
let request: NSFetchRequest<Item> = Item.fetchRequest()
let sortRequest = NSSortDescriptor(key: "order", ascending: true)
request.sortDescriptors = [sortRequest]
do {
toDoList = try context.fetch(request)
} catch {
print("the error is \(error)")
}
tableView.reloadData()
}
#objc func editItem () {
if tableView.isEditing {
tableView.isEditing = false
} else {
tableView.isEditing = true
}}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
context.delete(toDoList[indexPath.row])
saveItem()
self.toDoList.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
I would tackle this problem by having an index property in the Coredata entity; this index reflects the position of the element in the table view. In the swapAtFunction add the logic to switch the index properties of the two elements.
Then, when you fetch the entities, you add a predicate to your request, to sort the elements by the index property.
let fetchRequest = NSFetchRequest<EntityName>(entityName: "EntityName")
let sortDescripor = NSSortDescriptor(key: "index", ascending: true)
fetchRequest.sortDescriptors = [sortDescripor]
Then execute fetchRequest as you normally would, and assign the resulting array to the UICollectionView's Datasource.

Swift - Tableview not updating properly with search queries

I'm using the search bar controller with a tableview. I'm fetching the contacts on my phone to populate the tableview. Here's my code for this part.
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
It retrieves the contact with different phone numbers properly and then displays in the tableview. I've also added multi selection on the tableview to be able to select multiple contacts to continue with my flow of the app.
My issue is when I'm searching for the contact in the search bar , it always gives me the wrong contacts in my tableview. It comes up with the same name always at the top. Returns wrong contact
Now if I print my filteredcontact list , it returns the proper contact that should have been displayed but it is not displayed on the tableview. Here's my code for the search
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
And here's my full class:
class ContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var contactStore = CNContactStore()
var contacts = [ContractStruct]()
var filteredContacts = [ContractStruct]()
var setSelectedItems: Set<Int> = []
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
contactStore.requestAccess(for: .contacts) {(success, error) in
if success {
print("Authorisation Successful")
}
self.fetchContacts()
}
filteredContacts = contacts
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredContacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
}
else {
cell.accessoryType = .none
}
let contactToDisplay = contacts[indexPath.row]
cell.textLabel?.text = contactToDisplay.givenName
cell.detailTextLabel?.text = contactToDisplay.number
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
print(setSelectedItems)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
/*
// 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.destination.
// Pass the selected object to the new view controller.
}
*/
}
Just replace contacts[indexPath.row] to filteredContacts[indexPath.row] in cellForRowAt function of tableView delegate.
Because your filtered results stored in filteredContacts and your tableView delegate functions use filteredContacts
I had to replace filteredContacts[indexPath.row] in cellForRowAt for it to work.

How to save an array. So its the same after App restarts

I am wondering how to let my to-do-list be the same after the app is closed. In my code I am declaring an array right in the beginning and I want to know how I can save it updated for the user, after he restarted the App. I searched the web for some answers but only found old ideas about creating entities in storyboard. And I am pretty sure, that by now there has to be something more beautifully than adding it manually.
How can I save the array when it is getting updated, so it won't get lost after an app restart?
My Code:
import UIKit
var checklist = ["Item 1", "Item 2"]
class ChecklistViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource{
var newChecklistItemString: String?
var alertInputTextField: UITextField?
#IBOutlet weak var myTableView: UITableView!
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var selectedChecklist: [String] = []
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (checklist.count)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 18.0)
cell.textLabel?.text = checklist[indexPath.row]
if selectedChecklist.contains(checklist[indexPath.row]) {
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
return cell
}
// checkmarks when tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
selectedChecklist.append(checklist[indexPath.row])
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let value = checklist.remove(at: indexPath.row)
myTableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
addSlideMenuButton()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addNewObject(_ sender: Any) {
let alert = UIAlertController(title: "New Item", message: nil, preferredStyle: .alert)
alert.addTextField { (alertInputTextField) in
alertInputTextField.autocapitalizationType = .sentences
}
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Add", style: .default, handler: { (action) in
let textf = alert.textFields![0] as UITextField
if(textf.text != "")
{
checklist.append(textf.text!)
}
self.myTableView.reloadData()
}))
self.present(alert, animated: true, completion: nil)
}
}
For a simple string array use UserDefaults
Declare two methods to load and save data
func loadDefaults()
{
self.checklist = UserDefaults.standard.array(forKey: "checklist") as? [String] ?? []
}
func saveDefaults()
{
UserDefaults.standard.set(self.checklist, forKey: "checklist")
}
In viewDidLoad add
loadDefaults()
And right after adding and removing an item add
saveDefaults()
For more complex data other solutions like Core Data are preferable
Note:
Rather than always reloading the entire table view use the API to insert and delete single rows. The benefit is a nice animation.
In tableView:commit replace myTableView.reloadData() with
myTableView.deleteRows(at: [indexPath], with: .automatic)
and in the alert action replace the entire if expression with
if !textf.text!.isEmpty {
let indexPath = IndexPath(row: checklist.count, section: 0)
checklist.append(textf.text!)
myTableView.insertRows(at: [indexPath], with: .automatic)
}
And move the variable checklist into the class!
Find this solution:
// Use this code to fetch saved item list.
if let items = UserDefaults.standard.value(forKey: "ItemListArray") as? [String] {
print(items)
}
// Use this code to save your item list.
let itemList = ["Item 1", "Item 2", "Item 3", "Item 4"]
UserDefaults.standard.setValue(itemList, forKey: "ItemListArray")
// Use this code to remove item list
UserDefaults.standard.setValue(nil, forKey: "ItemListArray")
Check the code below:-
class ClassUserDefaults {
static let shared = ClassUserDefaults()
// MARK: - SETTER GETTER
var selectedChecklist: [String]? {
get {
guard let savedItem = (UserDefaults.standard.object(forKey: "selectedChecklist")) as? Data else { return nil }
guard let data = NSKeyedUnarchiver.unarchiveObject(with: savedItem) as? [String]? else { return nil}
return data
}
set {
guard let value = newValue else {
UserDefaults.standard.removeObject(forKey: "selectedChecklist")
return
}
let item = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(item, forKey: "selectedChecklist")
UserDefaults.standard.synchronize()
}
}
}
usage in your ViewController:-
ClassUserDefaults.shared.selectedChecklist = selectedChecklist
also you want to set wherever you want like:-
cell.textLabel?.text = ClassUserDefaults.shared.selectedChecklist[indexPath.row]
Hope it helps :)

Swift: How can I get the records from the database according to the cell pressed

Is it possible to get the data from the external database when a UItableViewCell is pressed?
I managed to create a UItableView where I am displaying the data from the database. If I press a cell then all the data that are linked to it should be displayed. For eg. if I have 4 main categories in the database such as TOOLS, OTHERS, SECURITY, PETS and each of them has its sub-catecory and are linked with each other in the database. So if I click on Pets, it should filter out and only Show me CATS, DOGS, COWS, LIONS. When I run this SQL I am able to get the information but cant figure it this out on Swift.
UItableViewCell is in my FirstviewController and its the Main Category .
When I click here it goes to my destination VC and has the table again in here.enter image description here
DestViewController is the sub-category
enter image description here
My CategoryList_ViewController.swift
import Foundation
import UIKit
import WebKit
class CategoryList_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let url = NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\cat.php")
let data = NSData(contentsOfURL: url!)
values = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CategoryList_TableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "catView" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let value = values[indexPath.row]
let controller = segue.destinationViewController as! SubCatergory_ViewController
controller.cate_Id = value["id"] as! String
controller.catTitleRec = value["NAME"] as! String
}
}
}
}
my SubCatergory_ViewController.swift
import Foundation
import UIKit
import WebKit
class SubCatergory_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var caID: UILabel!
#IBOutlet weak var catTitle_Label: UILabel!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
var catTitleRec = ""
var cate_Id = ""
override func viewDidLoad() {
super.viewDidLoad()
catTitle_Label.text = catTitleRec
caID.text = cate_Id
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let request = NSMutableURLRequest(URL: NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\subcat.php")!)
request.HTTPMethod = "GET"
let postString = "a=\(cate_Id)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! subCateListTableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
}
and my subcat.php
<?php
$connection = mysql_connect(........);
$catefilter = $_GET['a'];
if(!$connection){
die('Connection Failed');
}
else{
$dbconnect = #mysql_select_db($database_UNIASSIGNMENT, $connection);
if(!$dbconnect){
die('Could not connect to Database');
}
else{
$query = 'SELECT category_group.group_id , category.NAME FROM category_group LEFT JOIN category ON category.id = category_group.category_id WHERE category_group.group_id =' . $catefilter ;
$resultset = mysql_query($query, $connection);
$records= array();
while($r = mysql_fetch_assoc($resultset)){
$records[] = $r;
}
echo json_encode($records);
}
}
?>
My first VC works fine but my second VC doesnot get the data
Thanks for your time :)
SK
To access the cell that has been pressed, you need to call the didSelectRowAtIndexPath function.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let value = values[indexPath.row]
let vc = storyboard?.instantiateViewController(withIdentifier: "SubCatergory_ViewController") as! SubCatergory_ViewController
vc.cate_Id = value["NAME"] as! String
//self.navigationController?.pushViewController(vc, animated: true)
self.present(vc, animated: true, completion: nil)
}
First you get the value out of your values Array on the indexPark.row. Then you instantiate your second viewController.
Then you set your String value of cate_Id to the desired String value of your item value. And then you just need to present the new viewController.
If you're using a UINavigationController and you want a "back" button, then you use: self.navigationController?.pushViewController(vc, animated: true)
If you just want to present the viewController, you use self.present(vc, animated: true, completion: nil)
Comment or uncomment whatever presentation method you prefer.

IndexPath for variable row

I am using a UITableView with prototype cells. The main TableView is DiveDetails2VC and the prototype cell is based on DiveItemViewController via segue.
I need to save to parse the results, and have been able to save only row 0 to parse. I do not know how to set this up so that any row selected in the tableview is sent to parse. I am aware this is caused by the line in saveEntry:
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
but I do not know how to set the forRow statement to allow any row within the displayed array. There is only one section.
DiveItemViewController
class DiveItemViewController: UITableViewController, ItemDataProtocol
{
private let NumberOfSections: Int = 1
// MARK: - Public Properties
//
// This property is an object that conforms to the ItemDataSelectedProtocol. We use it to call the
// selectedItem method.
//
var itemDataSelectedDelegate: AnyObject?
private var itemData: Array<String> = Array<String>()
override func viewDidLoad()
{
super.viewDidLoad()
// Adds "+" to dive item selection so divers can add another item to the selected list
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(DiveItemViewController.AddItemButton(_:)))
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
// ---------------------------------------------------------------------------------------------
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell! = tableView.dequeueReusableCellWithIdentifier(Resource.DiveItemCell)
if self.itemData.isEmpty == false
{
cell.textLabel?.text = itemData[indexPath.row]
}
parseItem = cell.textLabel!.text!
return cell
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return self.NumberOfSections
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return itemData.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
if self.itemDataSelectedDelegate?.respondsToSelector(#selector(DiveDetails2VC.itemDataSelectedItem(_:))) != nil
{
(self.itemDataSelectedDelegate as! ItemDataSelectedProtocol).itemDataSelectedItem(indexPath.row)
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func tableView(tableView: UITableView, willDeselectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath?
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.None
return indexPath
}
func appendData(data: Array<String>) {
}
#IBAction func saveEntry (sender: AnyObject) {
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath)
let updateDivelog2Query = PFQuery(className: "divelog")
updateDivelog2Query.whereKey("uuid", equalTo: diveUUID)
updateDivelog2Query.getFirstObjectInBackgroundWithBlock {(objects: PFObject?, error: NSError?) -> Void in
if let updateDivelog2Object = objects {
updateDivelog2Object.setValue (self.itemData[indexPath.row], forKey: cell!.textLabel!.text!)
updateDivelog2Object.pinInBackground()
updateDivelog2Object.saveInBackgroundWithBlock {(done:Bool, error:NSError?) in
if done {
print ("ParseData UPDATED data saved")
} else {
updateDivelog2Object.saveEventually()
}
}}}
}
func itemTitle(title: String)
{
self.navigationItem.title = title
}
#IBAction func AddItemButton (sender: AnyObject) {
let alert = UIAlertController(title: "Add item",
message: "Add a new Item to your list",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default,
handler: { (action:UIAlertAction) -> Void in
let textField = alert.textFields!.first
self.itemData.append(textField!.text!)
self.tableView.reloadData()
self.appendData(self.itemData)
})
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)
tableView.reloadData()
}
func itemData(data: Array<String>)
{
self.itemData = data
}
}
Declare a var in your viewController:
var selectedIndexPath: NSIndexPath?
And then in your didSelectRowAtIndexPath, set this var with the selected indexPath like:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if let _ = self.selectedIndexPath {
selectedIndexPath = indexPath
}else{
selectedIndexPath = NSIndexPath(forRow: indexPath.row, inSection: indexPath.section)
}
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
if self.itemDataSelectedDelegate?.respondsToSelector(#selector(DiveDetails2VC.itemDataSelectedItem(_:))) != nil
{
(self.itemDataSelectedDelegate as! ItemDataSelectedProtocol).itemDataSelectedItem(indexPath.row)
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
And then use this selectedIndexPath like this in your saveEntry method:
#IBAction func saveEntry (sender: AnyObject) {
if let indexPath = selectedIndexPath {
let cell = tableView.cellForRowAtIndexPath(indexPath)
...
}
}
EDIT: Added ")" behind "inSection: indexPath.section)"

Resources