Can not set UISwitch outside of controller class - iphone

The iphone program is set up in the Utility Application model where you have a root view and two subviews (mainViewController & flipsideViewController) which are outlets.
If I try to set the UISwitch at rootViewController's viewDidLoad (with [flipsideViewController.switchInstance setOn:YES]), it doesn't work.
Within flipsideViewController, that method works but not outside of it. Any idea why? I can pass other methods...
Even if I pass a method to the flipsideViewController that then does the setOn method, it still doesn't work...
Any ideas?

Just as a 'sanity-check' (as others have put it to me) have you made sure your flipsideViewController variable is not null at the time you are calling the above code?

Related

Custom initialise subview added from storyboard

I have a subclass of UIViewController that I want to add from the storyboard.
So I'm using what seems the standard methodology:
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
[self addChildViewController:svc];
[self.view addSubview:svc.view];
Which is fine but what if I want to call a custom init method on the subview?
I can do something like:
svc = [svc initWithFoo:#"Hello"];
Which seems to have to go after the addSubview call inorder for it to work.
Is this the best way to do this?
Seems a bit unorthodox. Calling an init method on an object that has already been created seems like its no longer truly an init method.
Maybe I should call it setWithFoo: or something and not have it return anything?
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
will cause the SubViewController to be inited with it's - (id)initWithCoder:(NSCoder *)decoder {} method.
Override that method (don't forget to call super)
If you want to do additional setup to your view controller after you instantiate it form the storyboard you can create some methods in the view controller's class and call them after the instantiate method fo the storyboard.
But be careful, if you try to make changes on any UI component in those methods, they wont be applied, and probably the app will crash. So use those methods to set params to the View Controller like array of objects, or any kind of data, and apply the UI changes for the view controller's view in viewDidLoad/viewWillAppear/viewDidAppear methods of your view controller.
Essentially I think the answer is that you can't use custom initialisers on ViewControllers added from the storyboard. Instead you have to set properties directly or through a method at the appropriate time in the life cycle as stated above.
Also as mentioned, the VC will be instantiated through initWithCoder, so calling an additional initialiser might be superfluous(?).
I encountered problems trying to use a custom initialiser that contains a call to super if I called it before the subview was added. I would just get a blank view added, I think because the superclass doesn't seem to know about the storyboard at that point. I had more success removing the call to super but that seems wrong.
This case would be more pertinent when adding subviews to a scrollview. For simplicity I left this out of my example.

How to add the UI for one of the tab controller's using loadView when the rest were via Interface Builder?

I have a main window which has the UITabViewController as its root controller. I am using a nib file for this. In Interface Builder, two of the tabs have been wired to Controller_A, Nib_A and Controller_B, Nib_B but the 3rd tab only knows about Controller_C.
I assumed that this would mean that the loadView method of Controller_C would be automatically called since I haven't bothered to specify the NIB file. I want to lay this piece out programmatically. And it DOES indeed get called as I've confirmed by placing a breakpoint inside this method.
BUT when I switched over to Controller_C in the simulator, it comes up empty!
Here's what the loadView of Controller_C looks like:
- (void)loadView
{
[super loadView];
...
[self setTableView:formTableView];
[view addSubview:formTableView];
[self setView:view];
}
Any tips? What am I ignoring?
Looks like you are searching for:
-(void)viewDidLoad {
Here are the main things to check.
Click on your Controller_C in interface builder. In the Identity Inspector, make sure that the Class field is set to Controller_C.
In the Attributes Inspector, make sure the NIB Name field is blank.
If you have an existing Controller_C.xib laying around in your project, remove and delete it. The default implementation of loadView loads this file even if
Remove [super loadView]. Since you're building your view hierarchy in code, you shouldn't invoke the default implementation. You should explicitly allocate the controller's view as a local variable in loadView and set it using setView:.
Also, your comment on the other answer suggests that you may be confused about when/why loadView and initWithNibName:bundle: get called, so let me clarify:
loadView gets called to lazy load your controller's view the first time its view property gets accessed. This is true whether your view controller was constructed as an object in a NIB, or whether you constructed it yourself in code using initWithNibName:bundle:. The default implementation of loadView loads the NIB that was specified in initWithNibName:bundle: or in the NIB Name property in IB. If a NIB name wasn't specified, the default implementation looks for any NIB in the bundle that has the same name as your class and loads that NIB if one is found. If no appropriate NIB is found, then the default implementation of loadView just creates an empty view and sets that as your controller's view. When we build our own view hierarchy explicitly in loadView, we don't want any of these default behaviors, so we don't call [super loadView].
It seems loadView works as expected, the reason that my view was blank is because the datasource for my tableview was actually NIL. Earlier, I did not consider this scenario as I thought that it would at least present an empty table in such a case but apparently that was an incorrect assumption on my part. All this mistakenly led me to believe that the view wasn't being initialized properly.
#cduhn: Thanks, I had been following steps 1-3 already and it was really good to hear someone else give the same advice. The rest of what you said was educational for me as well.
Thanks Everyone.

Passing info to a delegate from a UIActionSheet

My understanding about passing data back to a delegate completely revolves around making a new view controller and having it conform to a protocol.
I am trying to get a time input back from a UIDatePicker set with the UIDatePickerModeCountDownTimer mode and I am running into issues.
Inside of Main1.m I create a UIActionSheet *action, and set everything up so that it presents itself with a UIDatePicker on a click. Inside of Main.m I also say:
main.delegate = self;
If this were not a UIActionSheet, I would make a protocol reference inside the new ViewController and then have the new vc pass data to a method that Main has, but I can't do that with a UIActionSheet!!
What am I missing? I assume there is something inherently different about Action Sheets, ut I can't figure it out.
Thanks for your help!!!
EDIT:
Sorry! I was giving a generic name to my view controller. It isn't actually Main.m, its FirstViewController.h/m
I didn't realize that my generic reference was getting mixed up with the Main.m file that is completely different than a vc.
I don't exactly understand why you're putting your delegate assignment in Main.m. I assume that you're setting up your UIActionSheet in a ViewController, and launching it from there. In this case, your ViewController is your delegate object. So you need to make sure that your ViewController implements the UIActionSheetDelegate. ie:
#interface SomeController : UIViewController <UIActionSheetDelegate>
Then you simply implement the required methods of that delegate in your view controller class, and that should do it. If I'm missing something about how you're implementing this, then you need to provide more code examples to examine.

IBOutlet is NIL when using Forward Declarations to call a class?

I have been having huge issues with this, so I drew a diagram...
alt text http://tomsfil.es/7bdead0a.png
I successfully get to the CLASS A - METHOD B but at that point, IBOutlet Z is Nil? :(
Any ideas?
note
Somebody told me it might be an Overrelease and to use NSZombieEnabled but that confused me
It's all a matter of when you call the class. Right after you create a view controller with initWithNibName, nothing is actually wired up yet - it's only after the view is created that IBOutlets are created and wired in.
One trick is that you can simply ask the view controller for .view, like so:
myViewController.view;
Then the view will be created and the IBOutlet will exist. A better method though, is to create properties on the view controller that you set, and then either in viewDidLoad, or in viewWillAppear you use those properties to set values for your outlets.

How to detect when a UIView has changed size?

I have a UIViewController that is initialised with a correct frame, however somewhere in my code the frame gets mangled and I'm having difficulty finding out where.
In situations like this it is usually handy to watch a variable in the debugger, however I have no way of accessing the controller->view->frame property in my variable view, since it isn't a variable, it's a property (surprisingly enough)
Drilling into the UIView in the variables display shows a few things but nothing I can relate to the frame, I thought perhaps that would be in layer but it isn't.
Is there any way to watch for changes in a private API? I guess not, since the variables are essentially 'hidden' and so you can't specify exactly what to watch.
Alternatively, what other approach could I use? I already tried subclassing UIView, setting my UIViewController's view to point to this subclass and breaking on the setFrame method but it didn't seem to work.
EDIT: the subclassing UIView method DID work, I just had to set the view to point to my test subclass in viewDidLoad and not the init method. Leaving this question open as I'm not sure if this is the best way of approaching this kind of problem...
Subclass your the view you want to track and rewrite the setFrame method:
#implementation MyTableView
- (void)setFrame:(CGRect)frame;
{
NSLog(#"%#", frame);
[super setFrame:frame];
}
#end
Then use the debugger to add a breakpoint to it and check when it gets called. Eventually, you'll see when the frame gets changed and where does the change comes from.
I discovered this can be done using key value observers.
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html
You could create an ivar, view2, and just assigned it to your view in your loadView method. That should enable you to watch it like a normal variable.