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.
Related
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];
My problem is:
I've created a project object. In this project object I need to call a method in a ViewController.
The method I need to call draws some objects in the ViewController principal view using a modified -
(void)drawRect:(CGRect)rect method.
The only thing I need to do is call this method on the actual instance (the instance that is created when the app starts) of the ViewController from a method in the project class.
The method created (to draw the objects) works. I tested it by calling it from the ViewDidLoad method of the ViewController. In the project method I tried for example this code:
-(void)drawProject {
UIStoryboard *mainStoryboard =[UIStoryboard storyboardWithName:#"Main" bundle:nil];
IYViewController *projectViewController = [[IYViewController alloc] init];
projectViewController = (IYViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"project"];
[projectViewController drawProject];
}
I named the principal, the target ViewController "project" in interface builder.
The problem is that anyway the ViewController instance that I create is not the instance of IYViewController that is displayed at runtime.
I didn't find any real good solution that works for me, so please help! Maybe the solution is create a delegate of a class but I didn't really understand that so please if this is the right solution help me code it!
Yes, the instance that you alloc and init is not the one that you load from the storybaoard. There is no need to alloc and init it. If you don't ARC then you even created a memory leak there.
-(void)drawProject {
UIStoryboard *mainStoryboard =[UIStoryboard storyboardWithName:#"Main" bundle:nil];
IYViewController *projectViewController;
projectViewController = (IYViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"project"];
[projectViewController drawProject];
}
Well, this will not solve the issue. (If comments could be formatted properly then I added a comment rather than an answer). Your real problem is somewhere else and I fear that you may not yet know how to explain it so that we understand it.
Give it a try. Explain in a bit more detail.
Are you sure that your drawProject is really executed? To which class belongs the drawProject Method that we are looking at?
What exactly do you do in drawRect.
Besides, drawRect is a method of a view, not a view controller. If you implemented that for a view controller then it may not be called at all.
I have added a Storyboard file to an app that initially had none. For some reason, I could not get my custom UIViewController to display correctly until I added this into didFinishLaunchingWithOptions:
ActivityViewController *viewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:NULL] instantiateViewControllerWithIdentifier:#"ActivityViewController"];
Why do I need to force the use of my storyboard like this? The iOS template projects (Single View, Master-Detail etc) doesn't need this.
Checklist:
Xcode Project Summary→Main Storyboard is set correctly to "MainStoryboard".
Interface Builder→Identity Inspector→Class is correctly set to "ActivityViewController".
Interface Builder→Identity Inspector→Storyboard ID is also set to "ActivityViewController", but this is only because it's needed by instantiateViewControllerWithIdentifier.
You do not need to call instantiateViewControllerWithIdentifier if you set Is Initial View Controller on your "ActivetyViewController" in the storyboard. The initial view controller will have an arrow pointing at it.
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.
I have this main menu view controller -thing, that, rather than being defined twice in my storyboard, with segues in between, calls pushViewController on a new instance of its own class. So it goes:
menu_a --> menu_a --> option_x
rather than
menu_a --> menu_b --> option_x
After pushing the view controller once, the navigationController loses track of the associated segues and I get the "Receiver has no segue with identifier" message. That is,
menu_a --> option_y
never produces this sort of error.
I've Googled and searched Stack Overflow for the past three hours with no luck.
I hope somebody out there has tried the same thing, and will want to elaborate on a workaround.
I can't guarantee this will work, but here goes:
Presumably because segues are a Storyboard feature, calling performSegue is referring back to your ViewController that was instantiated by the storyboard. As described in this question, it's possible to request your storyboard to instantiate a new ViewController from itself, rather than creating it manually (which is what I presume you're doing).
UIStoryboard* storyboard = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
UIViewController* dest = [storyboard instantiateViewControllerWithIdentifier:#"CustomController"];
Attempting a segue from a ViewController created this way may have more luck, as it should have the same segue information associated, while a manually created one wouldn't). It's just a theory - let me know if it works :)