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

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.

Related

Pass data from Collection View to Table view

I am a new learner, I am doing an assignment, stuck on this point. My target is when user click on a cell inside collection view, I have to go on table view and pass data to it (Which means that table view will have only one cell with data for selected collection view item).
I know I will go to table view programatically not possible through storyboard(If possible let me know) by using delegate method didSelectItemAtIndexPath
Can you explain the way to open table view from collection view cell click and how I will wrap data to pass to other controller (I think Segue? But how if we cannot use storyBoard). I am not getting clear there is no much help on internet in objective c? If you provide some pathway it will be good and if you explain it would be excellent??? Any helping material will be a plus
I am using XCode11 with objective c and not using XIB files Just working by storyboards
I also think segues is the way to solve your problem.
Set up the segue in storyboard and then inside the didSelectItemAtIndexPath set some variable with the data you want to pass and use performSegueWithIdentifier:sender to kick off the segue. Then override prepareForSegue:sender to transfer this data to the destinationViewController. You could use the sender to transfer the data from perform... to prepare... as well but I suggest for now just use some instance variable.

Replace style Segue issue

I am using a Replace style segue in UISplitViewController's DetailViewController. My question is - when I replace the VC with the "replace segue", where goes the old one, does it get destroyed? If so, how can I re-instantiate the previous VC, the segue doesn't point both ways, does it?
Reason: I am trying to make TWO Detail Views that swap depending on the row clicked in the UITable in the Master View.
So you want to keep the replaced view controller?
Do you ARC? If you do, then keep a strong reference to both view controllers. That should prevent them from being "destroyed".
If you don't then retain both view controller objects. That prevents them from being released until the release count is zero and then being deallocated.
When you re-display the now-not-destroyed view controller, make sure that you really reuse the existing object. Do not create a new one. (Most tutorials etc. should create a new one each time).

Retain View Controller when popped from Navigation Controller using ARC

I have two table views and a detail view being managed by a UINavigationController. When a row is selected on the second table, it pops to a detailed view allowing changes specific data represented by the row. I need to be able to switch between the UITableView and the UIViewController without losing any of the data that might have been changed in the UIViewControllers (button selections, text values entered in fields, etc).
Basically, once the UIViewController is presented, one should be able to switch back and forth between the table and detail view without losing any data.
The problem is, when a UIViewController is popped from the navigation controller, that memory is automatically released, and since I'm using ARC, I can't just keep a pointer to that with a retain command in the UITableView.
I know that I could manually rebuild the view each time its corresponding table row is selected, but I feel that might be a messy solution. Another option I've thought of is keeping an array of pushed UIViewControllers and checking if the selected table row corresponds with an existing value before a new one is created, but that might also get messy.
Any suggestions?
Your final wish in this back and forth of view is what you stated in your question: you want to switch between view controllers without losing any information of the actions performed in these controllers.
But if you think at how MVC pattern works, you should consider a view controller as the glue logic between the view and the model. The view is not persistent, that's why it is legitimate for ARC to get rid of the owning view controller when the view is no more needed. Instead what you should persist while your app is working is the model data only: the model data will be shared between the involved view controllers, the view controllers will be recreated each time and the corresponding views will be updated based on the model data. The only reason why the view controller should be kept alive is when its alloc-init-loadView takes too much (e.g.: the view is OpenGL backed) but in such case I would suggest you to keep a strong reference to it in the AppDelegate and ask it to refresh the content when the model data is replaced.
So basically what you should do is:
- select the table
- extract the model data associated to the table, including all information relevant for the view controller
- push the view controller; save all view modifications to the model
- when the view controller is popped, the model data will be returned only
- next time, when you push the view controller again, you will restore the model and re-init the view controller.
This approach is not complicated and gives you the possibility to structure the app in a clean way. Tomorrow you can change your view controller structure (that its view and the logic) without any impact in the communication with the other view controllers as this managed by the model passing only.
There are a couple of solutions to this, just like you suggested.
The array solution is highly inefficient because of memory issues.
The second solution you proposed is a lot more elegant. Just write your own init method in that view controller and init the view controller with data from a plist file
If I'm reading the question correctly, you've got a tableView and a detailView that are driven by the same model data. When changes to the model data are made in the detail view, you want those changes to persist.
If you update the model based on the state of the controls when the detail view is popped, then those changes will persist and the changes will be visible the next time you drill back down into the detail view.
You don't mention what form the table data takes, but let's assume it's an NSArray of NSMutableDictionaries. When you tap the row, the didSelectRowAtIndexPath: method will need to hand the dictionary from that array index to the detail view controller through a property on the detail controller. The detail view controller will update the dictionary values in the method that dismisses it.
The way to think of this is using the model-view-controller pattern. The table and detail view data is stored in the model; the views present the data; and the controllers are responsible for updating the model and navigating between views.

Best way to have UITableView within another table?

I have a grouped UITableView in class A and if you select a row in section 0, I want it to open up to another UITableView. In the first view, I have a lot of other methods and buttons and custom designed stuff, so I don't want to create another XIB for the other table view since I'll have to copy over all the methods and custom designed stuff. I was thinking creating another XIB, but subclassing the class under the original class A this way I can use the methods of class A without having to redefine them again in the new class. But I'm having problems with this. Is there a better way? Can I have two table views in one XIB, and just hide one till the other is called up? But that seems a little messy..
If you simply try subclassing the existing viewcontroller it will have the same info for the selected row, hence it would have to grow exponentially in order to make display the right UITableView.
If your concern is redefining methods, then simply create a class that will hold those particular methods and include it in the UITableViewControllers that will be using them, that way you will only define it once. This way you can simply create a new UITableViewController and push it into a navigation controller everytime you select a given cell.
As an alternative of showing all options within one UITableView you can try the following: you can probably try adding a UIScrollView inside the UITableViewCell. I would make it scroll horizontally while keeping the UITableView scroll vertically.

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!