Create UIView through code and add events in iphone - iphone

I have created a UIView and added label to it and latter assign it to Controller.
Now whenever I click on my View it shows me "EXC_BAD_ACCESS”.
Below is my code.
//create a UIView in App Delegate
UIView *viewPtr = [[[UIView alloc] initWithFrame:frmRect] autorelease];
//created a Button and added to UIView
UIButton *btnPointer = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnPointer.frame = cgframe; // provides both a position and a size
[btnPointer setTitle:btnLabelText forState:UIControlStateNormal];
[btnPointer addTarget:self action:#selector(generate:) forControlEvents:UIControlEventTouchUpInside];
[viewPtr addSubview:btnPointer];
//Now need to add this UIView to a controller
viewController.view = viewPtr;
I am able to display the button on the Form but when I click on the form or the button I get
"EXC_BAD_ACCESS”.

You should create the view in the .m file of your view controller like this.
- (void)loadView
{
UIView *viewPtr = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
//created a Button and added to UIView
UIButton *btnPointer = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnPointer.frame = cgframe; // provides both a position and a size
[btnPointer setTitle:btnLabelText forState:UIControlStateNormal];
[btnPointer addTarget:self action:#selector(generate:) forControlEvents:UIControlEventTouchUpInside];
[viewPtr addSubview:btnPointer];
//Now need to add this UIView to a controller
self.view = viewPtr;
[viewPtr release];
}
Hope this helps.
Thanks,
Madhup

Instead of use the autorelease
UIView *viewPtr = [[[UIView alloc] initWithFrame:frmRect] autorelease];
Create the UIView *viewPtr on the .h file, and only do the release in the dealloc method
So, you will have the declaration on your .h file
UIView *viewPtr;
And you .m file will be with the following lines, when you instantiate the viewPtr in the same place where you was doing previously, but without the autorelease, and the release on the dealloc method as follow:
viewPtr = [[UIView alloc] initWithFrame:frmRect];
.
.
.
.
.
.
.
.
- (void)dealloc {
[viewPtr release];
[super dealloc];
}
The autorelease is the main problem in your code, because when you do this, your UIView won't respond to any event.
Cheers,
VFN

What is self in [btnPointer addTarget:self ... ? Is generate: called? Have you tried debugging there?

As vfn says, this you get the error because you release the view too early. The question I would be asking is why is this case different?
Normally in an assignment like this:
viewController.view = viewPtr;
The viewPtr is retained and you would be correct to release it yourself. But look at the definition:
#property(nonatomic, retain) UIView *view
This means that any value is simply assigned and not automatically retained.

Related

When addSubview and release not working properly in added view

I'm created Class and it's add to the current view with non arc project. After that i'm releasing it as this.
TestViewController *tView=[[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
tView.view.frame=CGRectMake(10, 10,tView.view.frame.size.width , tView.view.frame.size.height);
[self.view addSubview:tView.view];
[tView release];
I added button to the TestViewController and when pressed it just crash and view this message from console.
-[TestViewController performSelector:withObject:withObject:]: message sent to deallocated instance
Anyone can explain the reason for that?
When you call [tView release]; TestViewController's dealloc method will automatically get called. And Objects of this class will be released. So Probably you have released that button in dealloc. That's why your app is crashing.
This is not the right way to do it.
You should create a custom view and add that view to self.view instead of adding viewcontroller's view.
Currently, you had declared TestViewController instance as local. So, that only it is getting crash while accessing the controls which are there in the instance.
Declare TestViewController instance in class level(ivar) and then use it.
Obviously, the target of your button is tView. [tView dealloc] is called after [tView release] as its retainCount decrease to 0.
You should declare tView as a private member variable, such as _tView, and call [_tView release] in your view controller's dealloc function.
#interface **
{
TestViewController *_tView;
}
if(!_tView){
_tView=[[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
}
_tView.view.frame=CGRectMake(10, 10,tView.view.frame.size.width , _tView.view.frame.size.height);
[self.view addSubview:_tView.view];
In iOS 5.*, custom container view controllers is supported. (http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html )
You can write code like this:
TestViewController *tView=[[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
tView.view.frame=CGRectMake(10, 10,tView.view.frame.size.width , tView.view.frame.size.height);
[self.view addSubview:tView.view];
[self addChildViewController:tView];
[tView didMoveToParentViewController:self];
[tView release];
you can use below code
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.yourViewController addSubview:button];
self.viewController means you have define your viewcontroller in .h file and then use you instance of the view controller to add your button.
then you can release your viewController [ViewController Release];

UIButtons not working on programmatically created UIView

I have a UIViewController which I want to display a UIView that renders as a menu. This menu will have several buttons on it. I wanted to reuse this menu a few different places in my app so I figured I would create a class called ViewFactory that has a method that returns a UIView with these buttons.
On my ViewController I call this method and get the returned UIView and add it as a subview.
This works just fine. I can see the view and all its buttons, however, the buttons do not respond to any touch events. Not sure why this is the case and curious to know what I am doing wrong.
Here is my code for the ViewFactoryClass:
- (UIView *) addCloseRow
{
// UIView container for everything else.
UIView *navRow = [[UIView alloc] initWithFrame:CGRectMake(0,225,350,45)];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.userInteractionEnabled = YES;
[navRow addSubview:button];
[button addTarget:self action:#selector(closeButtonTouchDownEvent) forControlEvents: UIControlEventTouchDown];
navRow.userInteractionEnabled = YES;
return navRow;
}
In my main NavigationController class here is how I am calling and getting the UIView:
ViewFactory *factory = [[ViewFactory alloc] init];
[self.navigationController.navigationBar addSubview:[factory MainNavigationUIView]];
Again, the UIView shows up but the buttons never respond to anything.
You added the button with target and selector for ViewFactoryClass
And now you are creating instance and trying to call an action from ViewFactory class.
You can change the method to something like this:
- (UIView *) addCloseRow : (id)object {
...
[button addTarget:[object class] action:#selector(closeButtonTouchDownEvent) forControlEvents: UIControlEventTouchDown];
...
}

How can I create a interface (UIView) in a different class and add on my screen

I want to create a different class with a view and call that class on screen.
When I run the app, the view does not appear. If I delete that structure and create the button on the main file, it works fine. When I put it on a different class, it does not work.
MyView.h
#import <UIKit/UIKit.h>
#interface viewHome : UIViewController
-(UIView*) myHome;
#end
MyView.m (Creating a button for test)
#import "viewHome.h"
#implementation viewHome
-(UIView*) myHome {
UIView * myScreen = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
myScreen.backgroundColor = [UIColor whiteColor];
UIButton * myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(100,100,100,44);
[myButton setTitle:#"Login" forState:UIControlStateNormal];
[myScreen addSubview:myButton];
return myScreen;
}
#end
viewController.m
[...]
- (void)viewDidLoad
{
[super viewDidLoad];
viewHome * fncScreen;
UIView * homeScreen = [fncScreen myHome];
[self.view addSubview:homeScreen];
}
Thanks
Its a bad practice to add one viewController's view as a subview to an another viewcontroller. (unless you are using certain classes/methods that let you have childViewControllers).
Its exactly for this reason, your view doesn't appear in one case, and appears in the other case.
try adding the -(UIView*) myHome method in your viewController.m, and do a
[self.view addsubview: [self myHome]];
here's a good SO post about Nested UIViewControllers:
Is it wise to "nest" UIViewControllers inside other UIViewControllers like you would UIViews?
You could call the method [fncScreen myHome] after allocation your view homeScreen.
like this -
UIView *homeScreen = [[UIView alloc] init];
homeScreen = [funScreen myHome];
[self.view addSubView: homeScreen];
[homeScreen release];
Hope this will help you.
One obvious mistake I see in your code is this line:
viewHome * fncScreen;
OK, that's a pointer declaration, but you didn't actually create the object.
You need something like this:
viewHome * fncScreen = [[viewHome alloc] init];
Then you can call methods on such initialized object.

removeFromSuperview not removing button from the view

removeFromSuperview not working Properly?
I added one button over another button.
When i try to remove the latter button from the view using removeFromSuperview function call , it does not worked.
the following Code works for me perfectly;
header file
#interface ViewController : UIViewController
{
UIButton *btnShadow;
}
#property (nonatomic,retain) UIButton *btnShadow;
implementation
#synthesize btnShadow;
-(void) vDrawGrayView
{
btnShadow = [[UIButton alloc] initWithFrame:CGRectMake(0, 44, 320, 416)];
btnShadow.backgroundColor = [UIColor colorWithRed:((CGFloat)79/255) green:((CGFloat)73/255) blue:((CGFloat)73/255) alpha:1];
[btnShadow addTarget:self action:#selector(HideKeyboard) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnShadow];
}
whenever you need to remove the button use:
[btnShadow removeFromSuperview];
note
Dont fotget to release the button and make sure you are removing the button that is on the front, you can make it in the front of the UIView by using:
[self.view bringSubviewToFront:btnShadow];
Good luck.

iPhone hand crafted views/controllers

I was wondering if anyone knew of any good online resources/tutorials for creating views and controllers programatically rather than via the interface builder. Everything I have looked at uses the interface builder and the created nibs, while the IB is ok I would like to have the option of developing these manually (both for practical reasons and get a good understanding of how it all fits together rather than the superficial one you get from dragging and dropping things).
My background is in java and I'm finding it slow and frustrating using the interface builder to develop views the way I would sometimes do them in Java, i.e. either
generate the source programatically from a domain model and then tweak the result if requried
use some meta-data and/or reflection and dynamically add the controls to the view
Also, once I have created a view is there anyway I can add it to the interface builder to make it available to use as a sub view on another view?
Thanks, Vic
The Interface Builder method creates "freeze-dried" objects that are re-created at runtime when you initialize the object from the NIB. It still does the same alloc and init stuff, using NSCoder objects to bring the objects in to memory.
If you want to have a view controller based on a particular NIB, you can then override the default init method and init it based on the NIB for that view controller. For example:
#implementation MyViewController
-(id) init {
if (self = [super initWithNibName:#"MyViewController" bundle:nil]) {
//other setup stuff
}
return self;
}
And when you want to display the MyViewController, you would simply call something like this:
- (void) showMyViewController {
MyViewController *viewController = [[[MyViewController alloc] init] autorelease];
[self presentModalViewController:viewController animated:YES];
}
Now, if you want to create your view manually instead of in Interface Builder, you don't have to change your -showMyViewController method at all. Get rid of your -init override, and instead override the -loadView method of your MyViewController to create it programmatically:
- (void) loadView {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(320,460)];
self.view = view;
[view release];
//Create a button
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
This example shows how to create the view and add a button to it. If you want to keep a reference to it, declare it the same way you would if you were using a NIB (without the IBOutlet/IBActions) and use self when assigning it. For example, your header might look like this:
#interface MyViewController : UIViewController {
UIButton *myButton;
}
- (void) pressedButton;
#property (nonatomic, retain) UIButton *myButton;
#end
And your class:
#implementation MyViewController
#synthesize myButton;
- (void) loadView {
//Create the view as above
self.myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
- (void) pressedButton {
//Do something interesting here
[[[[UIAlertView alloc] initWithTitle:#"Button Pressed" message:#"You totally just pressed the button" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK",nil] autorelease] show];
}
- (void) dealloc {
[myButton release];
[super dealloc];
}
I had the same issue a couple of months ago when I wanted to do all the iPhone development inside Emacs. To make a long story short: I'm not developing for the iPhone anymore :)
I'd still suggest you to check my question and some helpful answers here.
I typically don't use Interface builder too much for iPhone development. Usually I will create a view controller in code like this
MyUIViewControllerSubclass *controller = [[MyUIViewControllerSubclass alloc] initWithNibName:nil bundle:nil];
controller.someProperty = myModel;
[self presentModalViewController:controller];
[controller release];
Or something along those lines. Typically I create a subclass of UIViewController and that's where I layout my views and such. The views are subclasses of UIView (either things Apple provides like UIButton etc, or something I've created myself). If you read up on both UIViewController and UIView you should get a pretty good idea of how it works.