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.
Related
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.
which is faster ??
#interface ViewController : UIViewController
{
UIView *myView;
}
#end
#implementation ViewController
- (void)myInit(){
UIView *view = [[UIView alloc]init];
myView = view;
view.tag = 1;
}
- (void)viewDidLoad(){
[self myInit];
[self.view addSubview:myView];//accessing by variable
//OR
[self.view addSubView:[self.view viewWithTag:1];//accessing by tag
}
#end
In one you have a direct pointer access, in another you need to call a method, then find the indexed object and returning it to get the same object. I think you have your answer
It's useful to retrieve elements using "viewWithTag" if the elements were hooked to the cell programmatically (i.e. not defined in a NIB and hooked-up via IBOutlets)—this prevents multiple labels etc. to be created for each instance of the cell.Definitely using a variable and /or IBOUtlet in NIBS has the upper merit more ever because when we want to fetch a view via viewWithTag ,the compiler runs a for loop within its subViews and fetch the first view it finds with the given tag.Hence in case where you have two view with same tag ,using viewWithTag always have a major disadvantage.
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.
I am an objective C newb and relative programming novice in general, so your patience is appreciated. Inside a View Based Application template I am pulling this code out of myNameViewController.m and trying to insert it into a custom class. Everything transitions fine except this: [self.view addSubview:myImage]; I gather this is now calling the addSubview method of myObject, which does not exist....what is the correct way to insert the subview into the current view?
#import "myObject.h"
#implementation myObject
-(void)drawImage{
CGRect myImageRect = CGRectMake(0.0f, 0.0f, 70.0f, 70.0f);
UIImageView *myImage = [[UIImageView alloc] initWithFrame:myImageRect];
[myImage setImage:[UIImage imageNamed:#"test.png"]];
myImage.opaque = YES;
[self.view addSubview:myImage];
}
#end
Your myObject has to be a subclass of UIViewController for this to work, since this will give it the view property (same as the viewController you've copied the code from.
In myObject.h, your interface should read:
#interface myObject : UIViewController {
}
which means that it subClasses, or becomes a UIViewController at heart. It can do anything a regular UIViewController can do and will inherit all the same properties (such as a view), but since it only subclasses it you are able to add extra information that is specific to your own object.
The code you have copied is deriving from UIViewController (which is where the view property is defined). addSubview is a message on the UIView object.
So your myObject needs to be a subclass of UIViewController so that you can access its child view, or perhaps myObject is just a view on it's own (does myObject derive from UIView ?), in which case you can just add the UIImageView to the view hierarchy for myObject:
[self addSubview:myImage];
Update
You need to implement the drawRect message in your UIView subclass and draw on context. So something like:
#implementation ViewWhichDrawsItself
- (void)drawRect:(CGRect)rect
{
// get the drawing context
CGContextRef context = UIGraphicsGetCurrentContext ();
// draw on the context
...
}
I have a custom UIview which is created programmatically. How to associate to it a custom UIViewController (programmatically as well)
Thanks and regards,
Implement loadView in the UIViewController to create a view hierarchy programmatically without a nib file.
- (void)loadView {
// allocate the subclassed UIView, and set it as the UIViewController's main view
self.view = [[[UIViewSubclass alloc] initWithFrame:CGRectMake(0, 0, 320, 460)] autorelease];
}
You can continue setting up the view/subview hierarchy in two ways. One is to add them in the custom UIView's initialization method, like so:
// in the MyView.m file
- (id)initWithFrame:(CGRect)f {
if (self = [super initWithFrame:f]) {
// add subviews here
}
return self;
}
The second way is to continue using the loadView method implemented in the UIViewController subclass, and just using [self.view addSubview:anotherView]. (Alternatively, use the viewDidLoad method in the UIViewController subclass.)
Note: Replace initWithFrame: with whatever the custom UIView's initialization method is (e.g., initWithDelegate:).
Say the view you created is called newView and the controller is newController. The simple approach would be:
newController.view = newView;
But I'd rather subclass UIViewController and override its - (void)loadView and - (void)viewDidLoad methods and create and/or manipulate the view there - that's the way Apple wants you to do it, and for good reason.