View Controller With two different XIB's..Tricky - ios

I have a tricky question here..Please help..
I have One ViewController Called "DemoViewController" two different Xib's (Demo1Controller.xib & Demo2Controller.xib) are linked to the DemoViewController, Will load the Xib based upon the Condition..
I have navigation controller implemented in AppDelegate, Currently I am pushing this view controller(DemoViewController) with the XIB Demo1Controller, When User Taps a button in Demo1Controller, I need to load the same Viewcontroller i.e, DemoViewcontroller with Xib Demo2Controller..
Can this Possible?? Or Do i need to maintain the Different Classes for two Xib's
Let me know if you have any questions...

As a ViewController is just an object like any other object you can stack as many of them as you need on top of each other. Creating as many instances of that object as you want.
When you instantiate them you can do:
UIViewController *viewController = [[DemoViewController alloc] initWithNibName:#"Demo1Controller" bundle:nil];
or
UIViewController *viewController = [[DemoViewController alloc] initWithNibName:#"Demo2Controller" bundle:nil];
As long as the IBOutlets and delegate are set up correctly on both .xib's and they are set up using the same Custom class in IB. (Third icon from the left in the inspector panel, at the top.) If you fail to set them up properly it will simply crash on build and run.
And you can also check out a similar question I answered with a different approach some time ago.
Another approach

TRY THIS
- (id)init
{
if (YES)
self = [super initWithNibName:#"VC1" bundle:nil];
else
self = [super initWithNibName:#"VC2" bundle:nil];
return self;
}

I'm not sure if this is helpful to you, or appropriate for your situation, but I would probably suggest a slightly different approach (obviously, without knowing very much about your specific situation).
I would probably suggest that, rather than having one class have two different nibs, instead you have one class that has all of the common behaviour that these two 'screens' share, and then two concrete subclasses of this common parent class for each of the 'screens'. I am assuming that there are slight behavioural differences between the two.
You could then create an instance of your concrete subclasses with the specific nib name, as usual:
SubclassOneViewController *viewController = [[SubclassOneViewController alloc] initWithNibName:#"SubclassOneViewController" bundle:nil];

Related

How to change the variable of all tabs of the tabbarcontroller from first tab?

I have #property NSString *memberid; in tabbarcontrller.
I will use it in all of it's viewcontorllers.
I want to update the memberid by one of it's viewcontroller. so that other view controller can use the new value.
How can I update the NSString?
Do not listen to the others here, they're just feeding you bad practice. No offense, but hardcoding stuff is just not how it works. It's not how any of this works.
A simple and easy solution could be to add a class, some kind of "Manager" or "Service". You could call it MemberService. This class' job is to make all the work related to your member. I don't know your app but for what you're asking, this assumption is enough. Feel free to tweak this of course.
This class could be a singleton, depending on how that Memberworks. If you have more than one you could have a list of members inside that service class, or simply a property holding the values you need.
Here, I'll go for the simplest possible, assuming one member, so you can simply have a (constant?) field holding the member ID.
Now that service just needs to be available in your controllers, where you'll ask "Hey service, what's the ID number?" and he'll reply no matter where you ask from. With that architecture, you can ask 5 times, from 20 different tabs, it'll always work. No need to mix navigation controllers and whatnot.
You UI should not be responsible for managing your logic. Controllers deal with visuals, animations, etc. All the rest should be moved in logic classes (viewmodels, services, whatever).
Now, having the same property (even a singleton) available in multiple different controllers can be a little annoying, you still have to write down the property each time. A cleaner solution than the above is subclassing your UIViewControllers.
Simple as that : create a ... BaseViewController (you can find a sexier name than that) that inherits : UIViewController. Add a property, your singleton service, MemberService, and make sure to instantiate/prepare it in the viewDidLoad of BaseViewController ; maybe you can set that member ID and other stuff there, that's your choice.
Now, all your viewcontrollers used in tabs, change their superclass (on top of the file). Instead of : UIViewController, use your BaseViewController. Tadaa, they all always have that MemberService available, and you'll 100% sure no matter how many tabs, that you have a service available, and that it is loaded and ready to kick ass (because it's been prepared in the viewdidLoad).
I am doing something like this in one of my project,
NSArray *tabArr = [self.tabBarController viewControllers];
UINavigationController *navController1 = [tabArr objectAtIndex:1];
DraftViewController *dvc = [navController1.viewControllers firstObject];
dvc.screenTitle = self.screenTitle;
UINavigationController *navController3 = [tabArr objectAtIndex:3];
SentViewController *svc = [navController3.viewControllers firstObject];
svc.screenTitle = self.screenTitle;
UINavigationController *navController2 = [tabArr objectAtIndex:2];
OutboxViewController *ovc = [navController2.viewControllers firstObject];
ovc.screenTitle = self.screenTitle;
I am doing that in my first tab (first viewcontroller of tabbarcontroller)
I have embed navigationcontroller to every viewcontroller (tabs). So, i get first nav controller and then get VC(tab).
If you don't have nav controller embed to your tab VC then [tabArr objectAtIndex:index] returns view controller directly.
// In AppDelegate decalre one variable for tabcontroller , assign your tabcontroller to this variable, you can tabcontroller in use entire app. example code is here
Appdelegate *appdelegate = [[UIApplication sharedApplication] delegate];
appdelegate.tabController.memberid = #"1";

How do I transition to a different view controller programmatically?

Hey guys I'm trying to get my app to load a new view when a certain method is called. Inside the method I have the code:
ViewController *GameOverViewController = [[ViewController alloc] init];
[self presentViewController:GameOverViewController animated:YES completion:nil];
which is taken straight from How to switch views programmatically in a ViewController? (XCode iPhone).
Anyways, when I try to switch from my view controller called Game to a view controller called GameOverViewController I just get a ton of errors. Mainly
"Unknown receiver 'ViewController'; did you mean 'UIViewController'
And my app crashes. I'm obviously doing something wrong but I have no idea what that is exactly. Do I have to declare the GameOverViewController in my Game.h or in my appDelegate or something?
EDIT: Both view controllers are in the same main.Storyboard file if that matters
The unknown receiver message means that it can't find the class definition for the view controller class called ViewController. Is that really the name of the class you're using for your "game over" view controller? And if so, have you done the #import "ViewController.h" at the start of this .m file?
The fundamental problem is that it cannot find the class called ViewController.
Setting that aside, we don't generally instantiate new view controllers using alloc and init anymore, as that answer may have implied. That was a technique used with NIBs (and only worked if the NIB name matched the class name).
For new developers, I might encourage you to start with storyboards. Any modern tutorial should walk you through how to use storyboards. (Google "iOS storyboard tutorial" and you'll probably get lots of hits.)
If, for example, your storyboard has a scene with a "storyboard identifier" of GameOverViewController, then you might programmatically instantiate it and present it with something like:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"GameOverViewController"];
[self presentViewController:controller animated:YES completion:nil];
Or, if your storyboard had a segue from the current scene to the next scene, you'd make sure that segue had its own storyboard identifier, e.g. GameOverSegue, and then you'd perform it like so:
[self performSegueWithIdentifier:#"GameOverSegue" sender:self];
But find yourself a good introduction/tutorial on storyboards, as stumbling through Stack Overflow for answers will not be a very fruitful exercise.
For historical purposes, it's worth noting that if you were using NIBs, you can use the construct you referenced to in your question (but you'd have to make sure that (a) the class name was right; and (b) you did the #import that class header). And if the destination NIB had a different name than the class, you'd have to do something like:
UIViewController *controller = [[NSBundle mainBundle] loadNibNamed:#"nibname" owner:self options:nil]`;
[self presentViewController:controller animated:YES completion:nil];
But this is all academic unless you're using NIBs. If using storyboards, use one of the above patterns if you need to transition to a new scene programmatically.
You are in over your head. You should slow down and do some more studying or things are going to crash all over the place. I suggest going through a good book on iOS development and doing the exercises.
On to your question:
In the code you posted you're using a class "ViewController". There is no system-defined class "ViewController", although it is a common class name in example projects, and I think some of the project templates in Xcode even create a root view controller with that class name.
The name you give to your variable ("GameOverViewController" in the code above) is local and not really important. That's just a variable name. You can rename it lateForDinner if you want to, and it won't make any difference as long as you change that name everywhere in the scope in which it's defined.
The fact that you're being told that the class "ViewController" is unknown suggests that it hasn't been defined anywhere in your program.
You need an #interface and #implementation section that defines the ViewController class. Usually those will be in files called ViewController.h and ViewController.m, respectively. They might look something like this:
//ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController: UIViewController //Defines it as a subclass of UIViewController
// properties and methods of ViewController defined here
#end
And the .m file:
//ViewController.m
#implementation ViewController
// Implementation of ViewController methods go here.
#end
It's also possible to include the interfaces of multiple classes in a single header file, and the implementations of multiple classes in a single .m file, although I dislike this practice intensely. Keep it simple - one class per .h/.m file pair, with the file names identical to the class name.

Change/Modify Runtime User defined attribute before Instantiating ViewController

In short, I want to know "How to change Runtime User defined attributes before instantiating a View Controller"
Why I Need this
I am creating an application which uses multiple storyboards. I have a main storyboard with a UIViewController designated as LinkViewController. It has a string attribute, which tells it which storyboard has to be linked. now what I want to do is, I want to change that attribute at appDelegate & then instantiate the viewController. So far not able to do it.
This is what I am doing:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
EffLinkHomeVC *rootController = [storyboard instantiateViewControllerWithIdentifier:#"linkView"];
rootController.storyBoardName = #"wxyzForiPhone";
self.window.rootViewController = rootController;
I have found several other ways to work around. But I just want to know more clearly about altering "Runtime User defined attributes". Thank you all. :)
As far as I know you can only do this with proxy/external objects available in nibs.
Check the answer here to see a nice example of their usage.
By the looks of it this functionality is hidden or removed from storyboards. The only documented ways of configuring are static. In your case it would be statically configured with the properties from the storyboard you are using. If this suffices, you could use the key value mechanism to statically configure a different value for each storyboard.
Other than that you only have the normal post init viewController methods.

Do I have my Singleton Correctly setup? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What should my Objective-C singleton look like?
I am trying to understand the use of singletons. I have red to be careful with them, but also that they can have their positive uses.
My Scenario:
At the moment I have a test Project set up. One ViewController has a button that needs to perform an action.
The FirstViewController has a UIWebView on it.
I am using Storyboard and ContainerView, so I am able to see both ViewControllers at the same time.
In the First ViewController I have this code in my .m file:
static FirstViewController *sharedController = nil;
+ (FirstViewController *)sharedController {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
//BBCSermonTabBarViewController *myVC = (BBCSermonTabBarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"BBCNews"];
if(sharedController == nil)
sharedController = (FirstViewController *)[storyboard instantiateViewControllerWithIdentifier:#"firstViewController"];
return sharedController;
}
And I also have a method that changes the alpha it like so:
-(void)hideWebView
{
_webView.alpha = 0.3;
}
Now in my Second View controller I have this code:
-(IBAction)hideWebViewFromAnotherViewController
{
[[FirstViewController sharedController] hideWebView];
}
Should that action button now change the alpha of the webView in the other ViewController?
if not what am I doing wrong??
Thanks in advance:-)
I can appreciate your goal to understand singletons better, but I would suggest not using a singleton unless you have to.
I don't think it is appropriate in most UI scenarios(I have never needed one) to have singletons. I suggest one of the following methods for communicating between objects:
Hold a reference to objects that you want to communicate with. Simply add a property and save a reference to the class that needs to be called later. You can make it a weak reference if it works in your scenario.
Use the delegate pattern that is common with iOS/Objective-c apps. Same as above, except define a protocol instead. Normally the property is called delegate. This allows other views to communicate using a common interface.
Use notification center. I don't prefer this option for most cases, but if there is an event that a lot of views might need to know about, and you don't want to deal with passing references to objects, it might be a good option.
Singletons work best for non-UI code in my experience, when you actually need to rely on the singleton behavior of instantiating the class upon first use. In your situation it looks like the only reason you're using a singleton is to make that view controller accessible across your entire app.
For safety's sake, and because with libdispatch it's so easy, you should protect the singleton creator with a dispatch_once() call instead of doing an if() check.
+ (FirstViewController *)sharedController {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
static dispatch_once_t token;
dispatch_once(&token, ^{
sharedController = (FirstViewController *)[storyboard instantiateViewControllerWithIdentifier:#"firstViewController"];
});
return sharedController;
}
The token is used like a semaphore to protect the block and make sure it only gets called once during the run of your program; it's protected from races and simultaneous reads.
It should work. Potential problems: _webView is nil, [FirstViewController sharedController] is not returning a valid reference. Set a breakpoint on hideWebViewFromAnotherViewController and step through, making sure everything is defined when you think it is.

how to set view controller programmatically for subview in storyboard?

(Designed in storyboard , screenshot below) I have two subviews on my rootviewcontroller's view
In my code i want to assign a separate view controller to each subview. i.e Assign a tableViewController to the TableView.
I tried to do this in awakeFromNib (or ViewDidLoad) method but to no avail. The delegate method in my tableview controller are never called. I think storyboard does the job of loading the subviews here even before the tableviewcontroller i assign can do something.
self.myTableViewController = (TodoListViewController *)[[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
self.myTableView.delegate = self.myTableViewController;
self.myTableView.dataSource = self.myTableViewController;
self.myTableViewController.tableView = self.myTableView;
I am not sure if this is allowed when having views like this in storyboard or i am doing anything wrong ?
I came to this site as I had a similar problem. Actually I am doing the exact same thing: I have a viewcontroller with two subviews (all defined in a storyboard with lots of constraints).
in the containerviewcontroller in viewDidLoad I am doing the same calls as you do (but I defined the view first):
self.myTableViewController = (TodoListViewController *)[[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
self.myTableViewController.tableView = self.myTableView;
self.myTableView.delegate = self.myTableViewController;
self.myTableView.dataSource = self.myTableViewController;
That works for me (I guess, here is your problem: You don't have a navigation controller around it.... and be sure that the outlets of your tableview are really connected in the storyboard.).
But the real problem comes after the correct wiring. If you tab into a cell, you probably want to give some cellID to the nextView. As you have defined your tableviewcontroller manually, only your delegate method didSelectRowAtIndexPath gets called, but not the prepareForSegue.
I have played around with instantiating the viewcontroller from the storyboard
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"aStoryboard" bundle:nil];
self.myTableViewController = [storyboard instantiateViewControllerWithIdentifier:#"myTableViewID"];
but the segue did not get called. calling it directly (performSegueWithIdentifier:...) did not work as this tableviewcontroller is not managed by a navigation controller.
For me it ended up that the prepareForSegue method gets called in the containerViewController which can delegate the calls to its subviewcontrollers.
EDIT: Actually the real solution is DON'T. There is a "Container View" object which can be added to a view and defines a region of a view controller that can include a child view controller. This is what I really wanted to do.
Try again with your viewDidLoad method, that is the simplest answer. If the method is not loading you may have to look into the other things inside you method because if the application is large as they often are using storyboards you may have conflicting methods.
I would also look at this:
http://blog.waynehartman.com/archive/2012/01/07/uistoryboard-on-ios-5-the-good-the-bad-and-the.aspx
It shows the most common accidents people make when using any storyboard function programatically
Hope that helps!
Sounds like you want to write yourself a custom container controller, e.g. similar to UISplitViewController. Here's apple's brief docs on doing this in the UIViewController class reference. You could for example instantiate the children controllers programmatically in your container controller's viewDidLoad: or viewWillAppear: methods. I don't think you can get IB to instantiate the children for you, though, in the same way you can wire up say a tab bar or navigation controller's relationships to their children. (If there is a way, I'd like to know!)
It's typically easiest to set your classes and delegates all in the storyboard (as shown in numerous totorials including this one).
If you're really trying to put a scroll view and table view into the same view, then you'll need to look into UIViewController instantiateViewControllerWithIdentifier:, you can reasonably easily pull multiple view controllers (ideally with their proper classes, delegates and sources set in the storyboard) in and add their views to your outer wrapper view. I will say that I've done this and you can do cool things with it reasonably easily, but it usually isn't the cleanest way to do things.

Resources