Is it a good practice to subclass a UIViewController's subclass? - objective-c

Say you have a 2 subclass of tableView controller.
They both have the same header and footer view on top of the bottom of the header. They both implement pull to refresh.
They both have some common features.
The only different is one is for displaying the whole businesses, the other is for displaying only businesses you bookmark.
It looks like they both need to have the same parent class and the different is resolved on the child class. The differences are minor anyway.
I suppose the parent has it's own XIB, the children has it's own XIB.
Hmm... How would that work out? With the exception of container UIViewController, each controller should view a fullview of content. So which view should we display? The child or the superClass? Should child view add it's superclass subview?
Anyone have ever tried that?
Any code sample on the web that use this approach?

It sounds like, based on the business logic you explain, that everything is in common, except the list of data you're presenting. You could expose a property on your UITableViewController subclass to set the business objects that your tableview presents:
#interface JTBusinessesTableViewController : UITableViewController
#property (nonatomic, strong) NSArray *businesses;
#end
The code that instantiates this class would set the business objects:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self bookmarkedBusinesses];
[self.navigationController pushViewController:businessListings animated:YES]
The code for displaying all businesses isn't going to be much different:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self allBusinesses]; // Here we assign all of them
[self.navigationController pushViewController:businessListings animated:YES]
You're just selectively giving this view controller, the business objects to display.

Related

NSTableView reloadData external class

I have an NSTableview in class "spielplan", which I can reload easily with reloadData, but how can I reload the Table from my AppDelegate.m???
I think, there is a simple solution, but I don't get it!
Short answer: You shouldn't.
You class spielplan (which should be renamed to PMGameBoard) is probably a controller class that manages views, including the tableView. So it's the responsibility of this controller to reload the tableView's data should need be.
The external event from your app delegate, whatever it is, should be made available to the spielplan instance by some means of notification. The exact method of communication depends on the type of event (NSNotification, ...). See this objc.io article.
Create property or outlet (depends on do you use storyboard or not) in your spielplan.h file, for example
#property (nonatomic, strong) IBOutlets UITableView *myTableView;
and in the AppDelegate file get reference to spielplan object and call reload method:
[spielplan.myTableView reloadData];
If spielplan is subclass of UITableViewController you don't have to create outlet or property to the table view in your AppDelegate call:
[spielplan.tableView reloadData];
Bear in mind that when you try to get reference to your view controller from AppDelegate and the view controller is not in view hierarchy it can be deallocated or maybe it hasn't been allocate yet and call reloadData it doesn't make sense.

Passing Data(String) from Child VC to Parent VC using easiest Way

Passing Data(String) from Child View Controller to Parent VC using easiest Way .
i tried a Couple of ways , but got lost , can some one tell me the best way .
Srikanth is correct. If you have a segue from a view controller (our "first" view controller) to another (our "second" view controller), all you need to do is to create a property in the second one that points to the first one. You will just have the first view controller make sure to set that pointer before it performs the transition. Having done that, the second controller can update properties or invoke methods of the first controller.
For details, see Configuring the Destination Controller When a Segue is Triggered in the View Controller Programming Guide for information on how to set a property in the second view controller (in this case, that property will be a weak pointer to the first controller) in prepareForSegue. Then, as Srikanth says, the second controller can use that pointer to update properties in the first one.
So, in your second view controller, have a property (note carefully, it should be weak) that points back to the first view controller:
In SecondViewController.h:
#class FirstViewController;
#interface SecondViewController : UIViewController
#property (nonatomic, weak) FirstViewController *firstViewController;
#end
Then in the FirstViewController.m:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YourSegueIdentifierHere"])
{
[segue.destinationViewController setFirstViewController:self];
}
}
So, if your first view controller had, for example, a property of favoriteColor:
#interface FirstViewController : UIViewController
#property (nonatomic, strong) NSString *favoriteColor;
#end
Then, the second view controller could use its firstViewController property to update this favoriteColor, like so:
self.firstViewController.favoriteColor = #"Blue";
Clearly:
Replace FirstViewController and SecondViewController with the appropriate class names;
Make sure that your second view controller's .m file does an #import of the first view controller's .h; and
Make sure you've specified a segue identifier in Interface Builder for your segue from the first controller to the second one and adjust the prepareForSegue above, replacing YourSegueIdentifierHere with your identifier.
In iOS 6, you can also accomplish this via an unwind segue. You'd just have the prepareForSegue of the second view controller update the property of the unwind segue's destination controller (i.e. the first controller). What's nice is that unwind segues can go back an arbitrary number of levels, so for more complicated scenarios, it's very nice. It is iOS 6, or higher, only, though.
To do unwind segue's, first you must define an unwind action in the first view controller (identified as such by the combination of the IBAction return type and the UIStoryboardSegue parameter), e.g.:
- (IBAction)done:(UIStoryboardSegue *)segue
{
// do any clean up you want
}
Then, the second (or third or ...) view controller can create an unwind segue by control-dragging in Interface Builder from a button to the exit icon in the scene's dock. You can have the controller from which you're unwinding do the logical prepareForSegue to pass information back to the first view controller.
By the way, you used the terms "parent" and "child", but I wanted to make it clear that I assumed that you were not talking about the more advanced topic of view controller containment, in which a view controller is invoking other view controllers to facilitate the presentation of a single screen of information (as opposed to transitioning between different scenes in an app). As rdelmar notes in our comments below, the terms "parent" and "child" controllers, strictly speaking, more properly imply that one is using view controller containment.
Obviously, if you are using view controller containment, then clearly the discussion of segues, prepareForSegue, etc., don't apply. Furthermore, a properly implemented container view controller guarantees that the child controllers can actually use the UIViewController property of parentViewController, without needing to define our own property to reference the parent. All you need to do is to cast/define parentViewController to be the right subclass, and then you can access your subclassed properties very easily.
Best way is to have a property in the child view controller of type id or UIViewController. Set that value to parent view controller when you are creating the child.
Once you have access to parent view controller in the child view controller you can access its methods or properties.

Objective-C / iOS: Subclassing UITableViewController for a custom view

As we all know, table views in Cocoa Touch are one of the niftiest pieces of framework elements that's out there. As a convenience, Apple gave us a nice view controller class to encapsulate the functionality of a table view in a vc, the UITableViewController.
At the same time, there are times that we want to utilize the functionality of a table view without having it take up the whole screen. However, there seems to be no way to do this by subclassing UITableViewController. Instead, I had to hookup a table view and manually subscribe to the UITableViewDelegate and UITableViewDataSource. If I try to subclass UITableViewController, my app crashes before it can even put the view on-screen...
My question is, is there something I'm missing? When subclassing UITableViewController, I hook up my custom table view to the tableView property in UITableViewController. Is there something else I have to do?
UITableViewController only adds minor conveniences over UIViewController: it creates and positions the table view, hooks up the delegate & datasource (to itself, generally), passes the view controller editing property through to the table, and does a couple of useful UI bits when the view appears. (See [the docs][1] for details.)
Just about all of the above are either A) things that you're needing to change in order to have a non-fullscreen table, or B) things that you can do in a line or two each, and which UITableViewController only does for your convenience. For cases like this, you're better off using your own UIViewController subclass.
Step 1: Subclass UIViewController instead of UITableViewController
MyTableViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
Step 2: Use interface builder to drop a tableView and custom View
Step 3: Declare the tableView property as IBOutlet in your MyTableViewController header file and bind it to the tableView in the interface builder
IMHO, This process would give you more flexibility.

Associating a UITableView with a TableViewController

Can anyone describe how it is possible to have a TableViewController with its xib file having a at its root and the uitableview as a subview?
I believe the TVController somehow assumes that UITableView will fill the entire area.
Why is that?
I have a really specific need to build a kind of side and bottom tabbed interface with a UITableView as its main area. Pressing tabs changes the predicate for the fetchedresultscontroller etc etc.
The reason I want this is because of the breadth and depth of the data categories in the data model. I rally need to flatten the menu structure a lot...other wise with a table and navbar controller structure, user experience will be akin to sinking to ever deeper depths of a cavern!
My idea is tried and true in other paradigms...in iOS it almost looks like it's Apple's way or the highway. I am OK with APPLE of course no gripe.
But I really would like to create this.
I tried adding a new tableviewcontroller complete with xib and then removing the UITableView in IB and replacing with a UIView and a UITableView as a subview, hooking up (I believe) the delegate to the file's owner.
I created an IV tableView for when I want to reference it and again used IB to hook it up in IB
Try to run it and it whines that...
[UITableViewController loadView] loaded the "TabbedTableController" nib but didn't get a UITableView.'
Really can't seem to get my head around what the issue is here.
There doesn't appear to be anymore I can do to hook the UITableView up!
Any help would be terrific. I'll send you a Christmas card in desperation :^)
Also...why should it be so and how strict is this UITableView fullscreen thing?
Enlighten me if you can. The docs I have read don't want to.
Regards
Keith
A UITableViewController does assume that the root view (i.e. the controller's view property) will be a UITableView, thus the table view fills the screen. When you need a view that combines UITableView with other top level views, you will need to do a little more work but it's not hard:
Your view controller will not subclass UITableView. Instead, do this:
#interface MyViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) IBOutlet UITableView* tableView;
In Interface Builder, drop in a UITableView and whatever other controls you need. The table view can be any size and in any location in the view hierarchy. Also in Interface Builder, ctrl-drag from the table view to your VC and set the delegate and dataSource outlets, and ctrl-drag from your VC to the table view to set the tableView outlet.
Your view controller implementation should be the typical table view controller implementation: cellForRowAtIndexPath, etc.
A UITableViewController is more or less just all of the above work packaged up into a single unit for you.

Accessing Views created in Interface Builder

I've created a ChildViewController class, and then a nib that uses that class.
Then I created a BaseView, that includes some buttons, and some text that I'll be changing programmatically.
Then I created two more views (Boy and Girl), that I want to be able to lay behind the baseview so that the background color is different along with some graphics in an ImageView. I've named the views that I created in IB 'Boy' and 'Girl'...
But when I go back to my code where I'm calling ChildViewController, I'm not sure how to access the views I created so I can call insertSubView. Do I need to instantiate them in code? (in ViewDidLoad perhaps?) Does the nib create the instances when it loads?
I'm confused about how to handle multiple views for a single ViewController
edit =================
#Pablo Santa Cruz
Your answer assumes that i have two nibs and two view controllers (one for each view). I want to know if I can use one nib and one controller, and load in UIViews. It seems silly to create another nib and controller, when all want to do is change the background color and some graphics. Can't I programatically load in UIViews into a UIViewController?
Add IBOutlets in your App Controller class in Xcode then link them in IB (ctrl-click or right-click) from the connections tab in the Inspector to the object.
Then you will be able to send method calls to the objects.
The code in Xcode should look like this:
#interface AppController : NSObject
{
IBOutlet Girl girlIvarName1;
IBOutlet Boy boyIvarName2;
}
#end
You can access a UIView programatically by assigning a value to its tag property, which can be set in IB on the first tab of the inspector (Command 1)
The tag value defaults to zero, so if you want to access it specifically, make it non zero and unique. e.g. 100, which I will use in the example code below
Once the tag is set you can access the view using the following code in your UIViewController that was initWithNibName for the NIB containing the tagged view
UIView *aView = [self.view viewWithTag:100];
You can get instances for your IBuilder views with this piece of code:
boyViewController = [[BoyViewController alloc] initWithNibName:#"BoyViewController" bundle:nil];
girlViewController = [[GirlViewController alloc] initWithNibName:#"GirlViewController" bundle:nil];
Assuming your NIB file names are BoyViewController and GirlViewController. With those instances, you can do whatever you need to. I.E., adding them to a parent view (with addSubView message on the parent).