Swift 2: Update TableView from Separate Tab Bar Controller - swift

I am working with Swift 2.0 using XCode 7.3.
I currently have 2-Navigation-View-Controllers(NAV1 & NAV2) . Each of which that has their own separate Table-View-Controllers(TAB1 & TAB2) with corresponding Tables (TABLE1 & TABLE2).
TABLE1 has a separate child tables (TABLE1A...TABLE1Z) based on data.
The second table (TABLE2) has a way of changing data shared by table1 and its child tables (TABLE1 & TABLE1A...TABLE1Z) via a shared, singleton class. The 2-Navigation-View-Controllers(NAV1 & NAV2) are each Modals of a Tab-Bar-Controller (TAB_MAIN). The singelton class is accessible through any Controller and is a means of data-sharing.
TAB_MAIN
-NAV1
--TABLE1 (SINGLETON)
----TABLE1A (SINGELTON)
----... [potential for multiple sub-modals/tables](SINGLETON)
----TABLE1Z (SINGLETON)
-NAV2
--TABLE2 (SINGLETON)
What I would like is the following:
Changes to the Singleton data made in TABLE2, to update the data in TABLE1 and all its child modals immediately.
Note: Currently this is working by updating the data in the singleton class through function calls; i.e. objectClass.changeData()
Once the data is updated, via selection of a specific row in TABLE2, I would like to :
(a) change the currently selected tab to the first tab-view-controller
NAV1. Note this currently works via:
tabBarController?.selectedIndex = 1
(b) Update the displayed data in the table(s) for all the tables attached to the parent nav-controller for the first tab (NAV1).
(c) Unwind to the first tableView of the first tab (NAV1).
Currently what happens is, changes in NAV2->TABLE2 update the data and change the currently selected tab to whatever tableView NAV1 was left at, without changing the data.
Only by going to the parent (NAV1->TABLE1) of all sub-tables (i.e. TABLE1A...TABLE1Z, TABLE1AA, etc) does the data get reset and then by selecting the tableViews and drilling down does the data display in the child tables get properly updated.
I would like to 'unwind' to the top-most tableView of the first NAV1 controller from within the second NAV2 controller, or, failing that, update the information automatically on switching from NAV2->TABLE2 to any currently drilled-down NAV1->TABLEX.

Try use observer in NSNotifcationCenter in your NAV2-Table2. Add the observer in viewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(Table2ViewController.updateTable(_:)), name:"NotificationUpdateTable2", object: nil)
then call to update using postNotificationName after perform update in another view controller. this will reflect changes in table2
NSNotificationCenter.defaultCenter().postNotificationName("NotificationUpdateTable2", object: objectData)
remember to put comments to easier track changes since the observer can be triggered anywhere

Related

Load different arrays in the same table view controller based on a button press

I have a view controller and a table view contoller. In my view controller, I have 6 different buttons which when pressed should each load different arrays table view.
I made this diagram:
How should I proceed?
The solutions to this can range from very simple to more involved depending on how different the contents and behaviours are between your 6 arrays.
Simplest: All six arrays have the same structure and behave exactly the same in the table view.
--> Define a "current" array variable for your table view data source and copy the content of the selected array to it when a button is pressed. Then call reloadData.
A little more complex: All six arrays have the same structure but must show different content in the table view.
--> Use "Current" array variable as above but define multiple prototype cells in the table view. Maintain an internal variable in your view controller to determine which button is currently selected. In the getCellForRowAtIndexPath method, use your internal variable in a switch statement to perform the appropriate dequeuing and mapping of cell contents.
Most complex: Arrays have different structures and must show different content/behaviour.
---> Define a class for each array and implement the datasource and delegate methods specific to the structure and cell content/behaviour that you need. In your buttons, switch the table view's delegate to the corresponding class. (this will help keep the specifics of each array type cleanly separated)

NSTableVIew bound to NSArrayController doesn't save changes

I have a very simple project containing an NSTableView with 3 columns and buttons for adding new row, removing row and saving the data.
For the purposes of this project I want to save the values into the NSUserDefaults db AND to do all this with no coding, so the IB connections and properties are as follows:
Added Array Controller object via IB. Its Controller content is bound to Shared Users Defaults Controller (Controller Key:values, Model Key Path: myvalues), Handles Content as Compound Value checked.
Added the table view set to have 3 columns and set as view-based.
For the table view itself, its Content is bound to Array Controller (Controller Key arrangedObjects) and its Selection Indexes are bound to Array Controller (Controller Key selectionIndexes)
For each column of the table, the Table View Cell item (third in chain) Value is bound to Table Cell View (Controller Key empty, Model Key Path set to objectValue.xxxx where xxxx is an arbitrary name string for the column); also the Behavior attribute is set to "editable".
The add row and remove row buttons sent actions are connected to the Array Controller add and remove methods and the Save button sent action is linked to the Shared User Defaults save method.
When I run the project I can initially do "add", enter the values for the columns, click on Save, end execution and when I re-run it the data is shown. However, if I then try to change any of that data, the changes won’t be kept. If I add additional rows, and enter data that data is not kept (the rows will be there, just empty). Removing rows works as expected. (NOTE: also if I added several rows on the initial execution, only the first would have data on subsequent executions)
My question is: Why won’t data changes (after the first) work? It seems like there’s a missing layer somewhere.
I created a second project, very similar to first, but specified cell-based table rather than view-based; also the bindings are simpler with NO bindings for table-view but just directly bind table cells Value to Array Controller. This project works perfectly. Cell data can be edited, new row data entered, etc.
Any help would be appreciated
Since the cell-based table works as expected, with no coding, I'm going to use that for now. As for getting the view-based table to work properly, it appears (from Ken's notes and other SO threads) that the managed content is probably being updated properly but the user default controller is not being made aware of these changes. So a simple workaround would be to add a couple of lines of code, for example in AppDelegate applicationWillTerminate method:
let ac : NSArray = arrayController!.arrangedObjects as NSArray
NSUserDefaults.standardUserDefaults().setObject(ac, forKey: "myvalues")
where arrayController is an outlet for IB Array Controller.
(This is a bit of overkill as it would set the object every time the app runs, but you could also connect the SAVE button to a method that would set a Bool and then issue the setObject conditionally on SAVE being requested.)

Obj-C, catering for 'tap for more rows' and delete without core data?

I've been adding a temporary row to the end of my table view so I can limit the amount of data loaded / improve the speed of loading the view.
However, I didn't think about the delete feature. Where they swipe right to delete a row..
In my commitEditingStyle event I have, my check to see if it is a delete, then delete row from database, removeObjectAtIndex from my data array, beginUpdates, deleteRowsAtIndexPaths and if zero items left in my table insertRowsAtIndexPath with fade, so that my no transactions row will appear then endUpdates.
I did think when I add my tap for more rows I'd assign the row index to a variable and delete this row first in the commitEditingStyle event. However, I'd then have to query my database just to add another row, then add the tap for more rows row.
Which seems a lot of work for a quick fix.
Of course, I could just do a reloadData, but this seems really bad, but might be my only option.
I do eventually want to move to Core Data, but I really need to get this release out the door, its quite a complicated screen with segmented control for different data views and tap to edit the row in another view.
Can anyone advise me about some kind of trick / event I may have missed or another approach I could quickly use in this scenario ?
Make "tap for more" your table footer view instead of another cell. You will have to do this anyway if you move to core data and NSFetchedResultsController since hacking in an extra row becomes very complex then.
Your table footer view will just be a button (or some other view styled how you like it) - this can be created on viewDidLoad and set up with actions etc. It does not form part of your data model at all, so you have nothing extra to do in your datasource methods.

Refreshing/releasing 2nd tableview from previous query in drill down tableview

I have a drill down tableview that is using sqlite.
The first one is a tableview where i load some categories using a SQL query.
When i click a row it's using the following query to show the appropriate records for the category:
#"SELECT * FROM table WHERE category IS ('%#')", sharedSingleton.category];
This works.
When i click the back button on tableview 2 and return to the category tableview and then touch another category tableview2 still shows the rows for the category i selected the first time.
I'm new to this stuff but i searched a long time and tried releasing objects or set value's to nil but is doesn't seem to help.
Am i in the right direction, how can i refresh or release tableview2?
Thanks in advance.
Yes you are in the right direction.
When selecting a row table 1 you might be calling a method which loads the second table view and assigning the data to be loaded to the corresponding table view,Which is fetched and filled when delegate/ data source methods of table view is called.
You might have created tableview as a different view controller class, which is initialized and data is reloaded for the first time. But even though you are fetching the second set of data its not getting reloaded automatically even after you are assigning it.
After assigning the data you have fetched into the obect which distributes it to tableview Reload the table data once you assign it to. you could call the one line of code to do this
[tableview reloadData];
Regards,
Jackson Sunny Rodrigues

iPhone tableview does not create cell for added row

I have a SQLite DB containing tasks. Each task has a date, and there can be multiple tasks per date.
My app loads the data for one month only into a mutable dictionary. The key of each dictionary item is a string of the day of the month (1, 2, 3 ... 31). The corresponding value is an array of tasks for that date. Thus, for each day of the month, there is an array of 0 or more tasks.
The mutable dictionary is declared in the root viewcontroller. The root viewcontroller in Interface Builder is the dataSource and delegate of the table view. Somehow the app knows that the root viewcontroller gets its data from the mutable dictionary. I don't specify this, so I wonder what would happen if there were more than one dictionary, or maybe a dictionary and a mutable array? Nonetheless, this works without additional wiring. When the root viewcontroller loads the data into the table, each section header holds the date as its text, and lists all the tasks in individual cells underneath. Some headers have no cells.
Now, to modify a task, I have an "entry" viewcontroller. Selecting a task in the table causes the entry viewcontroller to load that task info into text fields, where I may change the title, date, details, or mark it as done. After editing, the entry viewcontroller unloads, the root (table) viewcontroller reloads, the view's tableView calls reloadData and the changes are apparent.
HERE'S THE PROBLEM: if I ADD a new task by clicking the + button on the nav controller, it takes me to the same entry viewcontroller, where I set the data. I return to the root viewcontroller via the same methods as when editing existing data. Yet no new cell has been created for the new data! If I close and reopen the app, the new data displays correctly.
Since data updates and inserts are written to the DB from the dictionary's arrays when the app closes, this means that the new item really was added to one of the arrays.
Summary: edit existing array item, and the new data is displayed when the table reloads its data. Add an array item, and it is ignored when the table reloads.
What's wrong?
You might add a line like this in your UITableViewController:
[self.tableView reloadData];
This will cause the entire UITableView to be reloaded. However, I believe the preferred method is:
[self.tableView insertRowsAtIndexPaths: indexPaths withRowAnimation: YES];
For this to work, you need to know where the row(s) will appear (the array of NSIndexPaths).
It may be easier to update the UITableViewController from within the "entry" ViewController.