tableView:cellForRowAtIndexPath: method question - objective-c

First of all I beg your pardon but I am a newbie and trying to learn Objective-C. I was studying the UITableView when I found this method:
tableView:cellForRowAtIndexPath:
I read the reference for UITableView and some examples but I don't understand one thing: what calls this method and what validates its parameters (eg. indexPath)?

This method is called by the UITableView when the table needs another cell to display. The table view calls the tableView:cellForRowAtIndexPath: method on the object pointed to with the table view's dataSource property.
So if you've got a view controller, you implement the tableView:cellForRowAtIndexPath: there, call [myTableView setDataSource:self] and the table view will call tableView:cellForRowAtIndexPath: once it needs to display a new cell for the given index path (row).
Of course, you also need to implement the other required method tableView:numberOfRowsInSection of the UITableViewDataSource protocol and maybe a few other of its methods. Otherwise the table view would even know how many sections and rows it should display.

Related

NSTableView delegate inside Nib

I have a NSWindowController as part of the work flow with NSDocument. The NSWindowController has an associated xib with a couple of NSTableViews. The datasource for these tableviews is a model defined by the NSDocument. I seem to be missing some information on setting up the outlets. If I setup all the outlets within IB, the datasource(s) are created at the time the nib is instantiated with their default init methods, which don't know about the model. By the time awakeFromNib is called, the datasource has already been queried by the tableview (numberOfRowsInTableView). My work-around is to not hook up the outlets for datasource. I get the model information in setDocument and set the delegates in windowDidLoad. This seems to work. How do I pass around a data model when setting the tableview datasource with IB? Since the outlets are not created when init is called (within the tableview datasource), how would I call out to get the model?
Thanks in advance.
There's an explicit note in the NSTabelView documentation:
Important: It’s possible that your data source methods for populating
the table view may be called before awakeFromNib is called if the data
source is specified in Interface Builder. You should defend against
this by having the data source’s numberOfRowsInTableView: method
return 0 for the number of rows when the data source has not yet been
configured. In awakeFromNib, when the data source is initialized you
should always call reloadData on the table view.

Is there a better way to load View Controllers from a table view?

This might be a very basic question, but I could not find the answer yet.
I have a UITableView that acts as a menu for my app. Each row on the table view, when selected, opens a different subclass of UIViewController.
At the moment my code works the same way used in the UICatlog example from Apple.
In the main view controller (the table view), each menu item is described in a dictionary in an array (menuList). Each dictionary contains an instance of the UIViewController subclass for that screen and other data about the menu item. When the user selects a row, the didSelectRow atIndexPath kicks in and calls the appropriate view controller, stored in the dictionary at that indexPath.row of the menuList array.
It seems to be very wasteful to alloc and init every single view controller when the table view first loads.
My question is: Is there a better way than the one demonstrated in UICatalog to alloc/init my view controller sublasses only when the associated row is tapped?
(I know I can use a complex if..else structure in the didSelectRow, but this results in an extremely long didSelectRow method and breaks encapsulation. I wonder if there is a cleaner way to do this, allocing and initing the appropriate view controller based on data from the dictionaries)
user1349768 try to use Storyboard, but this feature only works in iOs 4 and higher.
Just a suggestion ... put some reference to each view controller into NSArray and then initiate and segue to them when the row gets tapped on (and just get the reference from objectAtIndex:).
Although I could not find a better way to do this, the memory signature of each allocated View Controller is only 288 bytes. Since the solution suggested by apple is a lot more elegant and scalable then using a switch case statement, I left it as it is.

Get an event from an other view controller

I have two ViewController. The first contains and displays an array with values.
The second is a picker view (modal view controller) that permits to choose a columns to add on the array (with a button "ADD").
But, I don't know how retrieve an event when user click on "ADD" button to refresh my array because IBaction function and the array are not in the same controller.
Thanks for your help.
Protocols can be helpful for such situations.
A protocol is simply a list of method declarations, unattached to a class definition.
Protocols can be helpful in a number of scenarios, a common usage is to define methods that are to be implemented by other classes. A familiar example is when using a tableview, your class implements the cellForRowAtIndexPath method which asks for cell content to insert into a table – the cellForRowAtIndexPath method is defined within the UITableViewDataSource protocol.
Simple objective-c protocol example
You can also pass one local Variable when You press your add button and after that you reload your array in table view.
I think you want same like add contact add field function in simulaor.
Welcome.
I consider that,you have an array in first view controller that you want to access in second view controller on button event (IBAction):
Create Method in secondviewcontroller with array as parameter like this.
-(void)methodname:(nsmutablearray *)array;
Call the above method in first view controller and pass your array in this method when you navigate to second view controller by initializing it.
So, In second view controller you will get an filled array that you can use further.

delete UITableViewCell programmatically

I was wondering if it's possible to remove empty cells (empty = cells with no textLabel) after all the cells are created in a UITableView.
Why do you have empty cells? Are you using a consistent technique to control both the number of cells in your table and the content of those cells?
If you're using a UITableViewController, then your controller is automatically declared as the tableview's datasource. If you're using a UIViewController, then you'll declare it as comforming to the UITableViewDataSource protocol (and connect it up in Interface Builder).
Either way, as the tableview's datasource, your controller is required to implement two methods:
– tableView:cellForRowAtIndexPath:
– tableView:numberOfRowsInSection:
Presumably you're providing the data for the tableview with an array or other means inside -tableview:cellForRowAtIndexPath:. Inside this method the cell's label will be set from an entry in your array. And inside tableView:numberOfRowsInSection: you'll be doing something like [myArray count] to return the number of cells. tableview:cellForRowAtIndexPath will be called as many times as you tell it to (dictated by what you provide in tableview:numberOfRowsInSection:). If the datasource array changes, and you'd like to reflect the changes in your tableview, then you can call
[self.tableview reloadData]; //if inside a UITableViewController
[self.myTableViewOutlet reloadData]; //if inside a UIViewController
Note that reloadData reloads the entire tableview, so in some cases this may be computationally expensive. In this case, instead of calling reloadData you can focus on individual rows with the method: deleteRowsAtIndexPaths:withRowAnimation: (see UITableView Class Reference)
As the app delegate, you are responsible for providing cells. It is your responsibility to return every cell, and the number of cells in the table. Therefore as the app delegate you should have a means (be it by NSMutableArray or otherwise) to mutate the data that you return to the table view.

Re-use tableview from different controller: how to split didSelectRowAtIndexPath behaviour?

I'm currently working on my Favorites implementation. In the end, it should work the same as the favorites features in the Phone book on the iPhone.
I've the following set-up (besides other controllers and classes):
TabBarController (named mainTabBarController)
NavigationController with a Tableview (let's call it listNavController)
ViewController with some components for displaying row details (named detailViewController)
NavigationController with a TableView for favorite records (named favoritesNavController)
From the favoritesNavController, I want to select a row (from listNavController) so I can add a new entry to my Favorites tableview.
So, I decided to re-use my listNavController because it has all the functionality I need. Like searching, index, etc.
I've managed to show the listNavController from the mainTabBarController. So no problem here. When I select a row from the listNavController, it displays my detailViewController for that row. Of course, this was expected because that's in didSelectRowAtIndexPath in listNavController.
But, when I launch a listNavController from my favoritesNavController with the help of presentModelViewController, it still shows the detailViewController when selecting a row.
In this case, I want to return the selected row to my favoritesNavController. Then I can add it to my Favorite's list.
So, how do I differentiate this behaviour in code ? Should I use protocols, delegation, etc. ?
Any tips ?
With regards,
Rutger
It turned out that I was looking in the wrong direction.
The solution to the posted question is as follows:
I created a subclass of my listNavController and overrided the didSelectRowAtIndexPath method. Next I presented this new view controller with a navigation controller as a modal view (presentModalViewController).
Finally I set the delegate and a protocol for the subclassed view controller to the initiating class. This way I can present and dismiss the subclassed view controller from the same controller. A much more clean and MVC way to go!