Accessing UIView from UIViewController - iphone

I have added a UIView to a UIViewController using storyboards (See Image Below)
The problem is I cannot access anything from the UIView. I believe the issue is because when I init the class which UIView uses, I am creating a new instance of VASettingsView rather than using the one which has been added to the UIView frame using storyboards:
VARendererViewController.m
-(void)viewDidLoad{
...
// Initalise settings subview
self.settingsInit = [[VASettingsView alloc] init];
self.settingsInit.delegate = self;
....
}
-(void)update{
int test = [[self settingsInit] getTest];
NSLog(#"%d", test);
}
Returns 0, Should return '12345'
Any suggestions?

You are correct that you should not need to create a new VASettingsView in -viewDidLoad. Is settingsInit declared as an IBOutlet? You should be able to make a connection from the VASettingsView in Interface Builder to the outlet in your view controller.
-viewDidLoad is the method that is called after your nib is loaded; at that point all of the IBOutlets that were connected in your nib will be available for you to use. It is not necessary to create and set those properties.

Related

how to load custom view with xib on a xib or storyboard

I just want to load a custom view (with xib) on a viewcontoller's xib or stroy board.What is the best practice to do the same.
I have used awakeAfterUsingCoder function code below.
(id) awakeAfterUsingCoder:(NSCoder*)aDecoder
{
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder)
{
CustomView* theRealThing = (id) [CustomView view];
theRealThing.frame = self.frame;
theRealThing.autoresizingMask = self.autoresizingMask;
return theRealThing;
}
return self;
}
but after using this function my awakeFromNib started calling multiple time.
Please sugegst.
The correct answer currently linked to is overly complicated and buggy, as you have found out. There is a much more standard and better way to do this:
Create an empty XIB
Add a UIView to your XIB so that it is the only top-level object (aside from the proxies First Responder and File's Owner)
Change the class of your new UIView to CustomView
Instantiate the XIB and retrieve your CustomView instance like so:
CustomView *view = [[UINib nibWithNibName:#"CustomView" bundle:nil] instantiateWithOwner:self options:nil][0];
Add it to your view hierarchy in your view controller's viewDidLoad method:
[self.view addSubview:view];
Be sure to override -initWithCoder: in your CustomView subclass in case you need to do any custom initialization. I know this is a lot, so please let me know of any if these steps confuse you or if you get stuck.

TouchesBegan on a Sub-ViewController not getting called

I have a ViewController that responds to some touchEvents (touchesBegan, touchesMoved, etc...).
I've found that when I show this controller using presentModalViewController: it works just fine, but I'm trying to add it's View as a subview of another ParentViewController like so:
- (void)viewDidLoad
{
[super viewDidLoad];
//Add SubController
controller = [[SubViewController alloc] initWithNibName:#"SubViewController" bundle:nil];
controller.view.frame = CGRectMake(0, 30, 300, 130);
[view addSubview:controller.view];
[controller release];
}
When I do this, it gets added the parent view but it no longer responds to touch events. Is there a way to fix this?
Also, is there a better way to go about this? I know I probably could have used a View subclass for the child view, but it's supposed to use a Nib and I wasn't sure how to handle that without using a ViewController.
You're correct you should use a UIView subclass.
The easiest way to load it from a nib is to include the subview in your nib.
Just drop a UIView into the view connected to the original view controller.
Then with the view inside selected go to the identity inspector. It's the one that looks like a little ID card.
The very first field is called Custom Class.
Type the name of your UIView subclass here.
If you need a reference to this just create an IBOutlet in your original view controller and hook it up. That way you can set hidden = YES until you need it.
In your UIView subclass you might want to override
- (void)awakeFromNib
This will get called when the nib first unpacks.
for setting up any gesture recognizers, etc.
To load a nib directly into a view :
// Get the views created inside this xib
NSArray *views = [NSBundle mainBundle] loadNibNamed:#"myViewNib" owner:nil];
// There's probably only one in there, lets get it
UIView *myView = [views objectAtIndex:0];
// Do stuff . . .
[[self view] addSubview:myView];
You could try to call becomeFirstResponder in your subview and see whether it receives touchesBegan... It is probably so, but it will also possibly make the superview not receive touchesBegan if you require it...

Bug with UIView frame property?

I am initializing a new UIViewCOntroller object.
then attempting to set its view's position of stage but I am having some trouble.
here is the code I am using
Note: this code is placed in the application main UIViewController's viewDidLoad method
UIViewController * cont = [[UIViewController alloc] init];
cont.view.backgroundColor = [UIColor redColor];
CGRect rect = CGRectMake(100, 0, 320, 480);
cont.view.frame = rect;
this code is still positioning the subview at (0,0) instead of (100,0)
However, if I introduce a decimal, such as using 320.01 (for the width value) or 480.01 (for the height value). The view would be positioned correctly.
It seems that if I use a size with an exact width:320.0 height: 480.0,
the origin will always be set to (0,0) !!!
This is a bit strange. I was hoping that someone could explain why this is happening, and possibly how it may be resolved.
Cheers ....
NSLog the value of cont.view and I think you will find it to be nil, which explains why nothing's happening. This is not the normal way to create a UIViewController -- it's not wrong to create one programmatically, but 99.99% of the time UIViewController subclasses are created with the main UIView in a .xib file. A freshly created UIViewController object has a nil "view" member, so you've got to initialize it somehow, either by loading a .xib:
MyViewController *vc = [[[MyViewController alloc] initWithNibName#"MyViewController" bundle:nil] autorelease];
or manually creating the view:
MyViewController *vc = [[[MyViewController alloc] init] autorelease];
UIView *theView = [[[UIView alloc] initWithFrame:viewframe] autorelease];
vc.view = theView;
Then you can move the view's frame to your heart's content, but moving the base view of a view controller is usually not what you want to do, you want to create sub-views and move those around.
[[UIViewController alloc]init] is wrong. The designated initializer for UIViewController is initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle. Even that does not necessarily initialize the view outlet to an actual UIView immediately. You need to subclass UIViewController and perform your customisations in the viewDidLoad method of that subclass.
In the interim is likely that view is nil so you can try setting whatever properties of it you like without anything ever happening.
I think you should be able to use
-(void) loadView {
[super loadView];
//create your views programmatically here
}
in order to create your viewController programmatically and avoid the IB. Normally the IB calls this method for you when your 'view' property is nil, however if you're avoid the IB make sure to include the above method so your view property is not nil.

Create a custom UIView as a tableHeaderView programmatically

I want to create a 'detail view' in my navigation-based app similar to the address book app.
I want to create a UIView that has an UIImageView and a UILabel that I can pass to a UITableVIew's tableHeaderView property when pushed by a navigation controller. The label text and image must take information from the managed object context when it loads.
I started trying to do this using IB, but go fed up when the label text wouldn't update, regardless of where I put the myView.UILabel.text = #"some new text". It just kept presenting the text I entered in the IB inspector window.
So without using IB, how would I go about creating a UIView that has a UILabel and a UIImageView in it?
Should I be creating a new class that is a sub-class of UIViewController or just UIView?
How do I go about creating the sub-views for the label and image?
Where should the text and image URL be set in code? (viewDidLoad or loadView or viewWillLoad)(UIView, UIViewController, detailViewController)?
If you started using IB and the UILabel text wouldn't update, sounds like the IBOutlet of your view controller isn't correctly connected to the label in IB.
Hopefully that will fix your problem with using IB. And in the viewController code, you should update that text in viewDidLoad.
But if you want to do this programmatically, I would make a subclass of UIView (not UIViewController).
And I would override initWithFrame and do all the setup there.
Something like the following:
myView.m
#implementation myView
#synthesize imageView, myLabel;
- (id) initWithFrame:(CGRect) frame
{
if (self = [super initWithFrame:frame]) {
// Setup your image view and add it to the view.
self.imageView = [[[UIImageView alloc] initWithFrame:initWithFrame:frame] autorelease];
self.imageView.image = ...
[self addSubview:self.imageView];
// Setup your label
self.myLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
self.myLabel.text = #"whatever you like";
[self addSubview:self.myLabel];
}
return self;
}
Make sure to clean up memory properly in the dealloc method of course depending on whether you like make class properties vs class variables.

How to reference a subview without outlet

Just beginning with iPhone development i seem to miss something fundamental.
In a View based application i'm adding programaticaly a UIView subclass in the ViewController implementation file and can set a value:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect myRect = CGRectMake(20, 50, 250, 320);
GraphView *graphView = [[GraphView alloc] initWithFrame:myRect];
[self.view addSubview:graphView];
graphView.myString = #"Working here";
}
When i try to change the same value with an action in the same file, the Build fails because graphView is undeclared:
- (void)puschButton1 {
graphView.myString = #"Not working here";
}
Because I use a UIView subclass there is no outlet for my GraphView instance.
How can i get a reference to my subview? Or should this be done in another way?
Thanks in advance
Frank
The easiest solution is to make graphView an instance variable for your view controller, instead of declaring it in viewDidLoad.
Put something like this in your .h file:
#class GraphView;
#interface MyViewController : UIViewController {
GraphView *graphView;
}
// ... method declarations ...
#end
If you don't want to do that, another way is to set graphView's tag property, and then call the superview's viewWithTag: method to retrieve the view when you need it.
I'm not sure what you mean by "Because I use a UIView subclass there is no outlet for my GraphView instance." You generally declare outlets on your controller class, and it doesn't matter whether you are using a subclass of UIView.
As an aside, I'll note that you should probably release that GraphView at some point, or you'll have a memory leak.
You could store graphView as a class variable.
EDIT: note that addSubview will increase the retain count of the object, somewhere in your class you will need to balance the alloc with a release and the addSubview with a removeFromSuperview or a release.