I created the following class to get a toolbar with colored images
#interface likeUIBarButtonItem : UIBarButtonItem
- (id) initWithStatus: (enum ApartmentLikeStatus)p_status;
#end
and the m file looks like this:
- (IBAction) likeStatus_Clicked: (id) sender
{
self.numberOfClicks++;
[self.statusButton setImage:[self getStatusImage] forState:UIControlStateNormal];
}
- (id) initWithStatus: (enum ApartmentLikeStatus)p_status
{
self.statusButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.statusButton setImage:[self getStatusImage] forState:UIControlStateNormal];
[self.statusButton addTarget:self action:#selector(likeStatus_Clicked:) forControlEvents:UIControlEventTouchUpInside];
[self.statusButton setFrame:CGRectMake(0, 0, 20, 20)];
self = [[likeUIBarButtonItem alloc] initWithCustomView:self.statusButton];
return self;
}
in the view controller I do the following:
likeUIBarButtonItem* stausBtn = [[likeUIBarButtonItem alloc] initWithStatus:self.apartmentToShow.userLikness];
// List of toolbaritems
NSArray* toolbarItems = [NSArray arrayWithObjects: stausBtn, nil];
self.toolbarItems = toolbarItems;
self.navigationController.toolbarHidden = NO;
the button gets displayed but when clicking it i get an assembly code
0x120a09f: movl (%edi), %esi <-- thread 1: EXC_BAD_ACCESS (code=2 address=0x0)
although my statusButton is declared (strong, nonatomic) my guess it gets released somewhere between the init and the call to the function, is that the case or is it something else? and whatever it is how do I fix it?
That's not how you override an init* method.
You might be better off with something like this
- (instancetype)initWithStatus:(enum ApartmentLikeStatus)status
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[self getStatusImage] forState:UIControlStateNormal];
[button addTarget:self action:#selector(likeStatus_Clicked:) forControlEvents:UIControlEventTouchUpInside];
[button setFrame:CGRectMake(0, 0, 20, 20)];
self = [super initWithCustomView:button];
if (self) {
self.statusButton = button;
}
return self;
}
The problem with your version is that you create a button and assign it to self but then you reassign self to a completely new object at the end. So the initial self probably be released immediately as no one else can get a handle on it, which basically means you are passing a dangling pointer into the initWithCustomView: method
Related
Okay, so this is pretty weird; before upgrading to the final GMseed of Xcode my buttons worked perfectly fine...
Now I can't even do them on a super simple scale without the program crashing on click.
The absolute most bizarre aspect is that it works SOME of the time, but like 85%, it just crashes; and when it does work, it'll crash after extensive use.
Here is my code (stripped down to the simplest button implementation I could think of):
#interface TESTViewController ()
{
UIButton *button;
}
#end
#implementation TESTViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self addButton];
[button addTarget:self action:#selector(buttonPressed)
forControlEvents:UIControlEventTouchDown];
}
- (void)addButton
{
button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 80, 45)];
[button setTitle:#"CLICK" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:button];
}
- (void)buttonPressed
{
NSLog(#"WORKED");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
TESTViewController *test = [[TESTViewController alloc] init];
[self.window addSubview:test.view];
return YES;
}
I've tried creating the button in the init function, viewDidLoad -- neither works consistently, though viewDidLoad seems to work a little more frequently...
I tried -(void) addButton:(UIButton*)button as well
Using:
[button addTarget:self action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchDown];
--No difference.
I am at a total loss. I tried looking it up here on the forums, but unfortunately most of it refers to programming with IBActions.
The error I get is bad access
So my guess is that when the button is clicked, it's not actually accessing the buttonPressed function but something else entirely... I have no clue as to why this would be the case...
Thanks for any help!
The problem is in your "didFinishLaunchingWithOptions" method. Here you are creating a local object which gets Deallocated i.e "TESTViewController *test = [[TESTViewController alloc] init]".
You should retain this object, so try making it a property and use "self.test = [[TESTViewController alloc] init]". It will work.
Also conventionally you should use rootViewController rather adding your viewController to windows's subview.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.test = [[TESTViewController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = self.test;
[self.window makeKeyAndVisible];
return YES;
}
I think you have a memory leak on that Button object are you using ARC or manual memory management? If manual make sure you retain it. If it is ARC use a property and the compiler will do the rest of the work
#property (nonatomic, strong) UIButton *button;
try it this way
- (void)addButton
{
button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 80, 45)];
[button addTarget:self action:#selector(buttonPressed)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"CLICK" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:button];
}
and remove
[button addTarget:self action:#selector(buttonPressed)
forControlEvents:UIControlEventTouchDown];
this line from viewDidLoad
I am not sure if this is the cause of the crash but actions (like your buttonPressed) should have a sender parameter:
[button addTarget:self action:#selector(buttonPressed:)
- (void)buttonPressed:(id)sender
{
...
}
To define a button programatically use the buttonWithType method, Try this
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(buttonPressed)
forControlEvents: UIControlEventTouchUpInside];//Any control event type
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, 80, 45);
[view addSubview:button];
I tried to ask this question, but somehow I failed to express myself right I guess so I deleted it and started fresh.
I have a hierarchy:- ViewController => UIView => Stepper
Here is my code of the UIView:-
#implementation Controls
#synthesize m_numColumn=_whatever;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
int i;
m_numColumn= [[UIStepper alloc]init];
m_numColumn.frame = CGRectMake(1, 1, 30, 30);
m_numColumn.autorepeat= FALSE;
[m_numColumn setValue:2];
m_displayColumnNum= [[UILabel alloc]init];
m_displayColumnNum.frame = CGRectMake(30, 30, 60, 30);
// m_displayColumnNum.backgroundColor =lgammaf(<#float#>);
// m_displayColumnNum.text= [NSString stringWithFormat:#"aaaaaa"];
i= m_numColumn.value;
m_displayColumnNum.text= [NSString stringWithFormat:#"%d",i];
[self addSubview:m_numColumn];
[self addSubview:m_displayColumnNum];
// Controls.delegate = [m_numColumn.navigationController.viewControllers objectAtIndex:0];
[m_numColumn addTarget:self action:#selector(stepperChanged:) forControlEvents:UIControlEventTouchUpInside];
//[m_numColumn setdelegate];
}
return self;
}
The important line here is:
[m_numColumn addTarget:self action:#selector(stepperChanged:) forControlEvents:UIControlEventTouchUpInside];
What I would like is to react on that event in the UIViewController (parent object). How do I do that?
Is the problem that you don't get the event? I have always used UIStepper with "UIControlEventValueChanged", in your case it should be:
[m_numColumn addTarget:self action:#selector(stepperChanged:) forControlEvents:UIControlEventValueChanged];
there is the point of the controlEvents you are listening to, but there is also a problem with the target
[m_numColumn addTarget:self action:#selector(stepperChanged:) forControlEvents:UIControlEventTouchUpInside];
you shouldn't use "self" which is a reference to your view and not your view controller, either use a "myController" variable or do this method inside your controller
I am adding a button in UIScrollView in StoryBoard
Below is the code i am using.
-(void)addScrollView
{
for(int i=0;i<[array count];i++)
{
UIScrollView *subScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 400, SUBSCROLLVIEW_WIDTH, SUBSCROLLVIEW_HEIGHT)];
UITextView *txtVwDetail = [[UITextView alloc] initWithFrame:CGRectMake(342, 0, TEXTVIEW_WIDTH, TEXTVIEW_HEIGHT)];
txtVwDetail.text = SAMPLE_STRING;
[self addSubScrollView:subScrollView];
[self.view addSubview:subScrollView];
[self.view addSubview:txtVwDetail];
}
}
-(void)addSubScrollView:(UIScrollView *)aSubScrollView
{
for(int i=0;i<[array count];i++)
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
aButton.frame = CGRectMake(intBtnX, (aSubScrollView.frame.size.height - 80)/2, 50, 80);
[aButton setImage:[UIImage imageNamed:[self.items objectAtIndex:i]] forState:UIControlStateNormal];
**[aButton addTarget:self action:#selector(btnSubImageClicked) forControlEvents:UIControlEventTouchUpInside];**
aSubScrollView.contentSize = CGSizeMake(intScrollViewWidth, aSubScrollView.frame.size.height);
[aSubScrollView addSubview:aButton];
}
}
In addSubScrollView method I have added Button and its click event which is getting crashed.
-(void)btnSubImageClicked
{
NSLog(#"btnSubImageClicked");
}
I am having scenario as
MyMainViewController is the sourceViewController for my created customSegue which is the UIStoryboardSegue class
MyMainViewController having a UIView as PlaceHolderView in which I am adding MydestinationViewContoller's View which is this Scrollview
-(void)perform
{
BrowseScreenVC *srcObj = (BrowseScreenVC *)[self sourceViewController];
UIViewController *dstObj = (UIViewController *)[self destinationViewController];
for(UIView *vw in srcObj.viewPlaceHolder.subviews)
{
[vw removeFromSuperview];
}
NSLog(#"dest : %#",dstObj.view);
NSLog(#"destobj :%#",dstObj);
srcObj.currentViewController = dstObj;
[srcObj.viewPlaceHolder addSubview:[dstObj.view retain]];
}
UPDATE
With answer I also have to change the line
srcObj.currentViewController = dstObj;
to
srcObj.addChildViewController = dstObj;
to make it working
you have to add target as follow:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
#selector(), within these braces you have to provide the method that you want to perform. the ":" represents that the method has some argument. In this case the argument would be the button itself that is calling the method.
You have to implement your method then its signature would look like this
- (void)btnSubImageClicked:(id)sender{
// sender would be the button that is calling the method. you can use this object according to your requirements if you want.
// your code
}
if you want to call this method from somewhere else as well you can call it by passing sender argument nil. e.g [self btnSubImageClicked:nil];
Your action needs to accept an (id) sender argument, even if you are not using it:
-(void)btnSubImageClicked:(id) sender
{
NSLog(#"btnSubImageClicked");
}
In the addSubScrollView:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Button target should like
-(void) btnSubImageClicked:(id)sender{}
try this.
Updated:-
Please correct your code,change this line
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Now working i checked.
Instead of
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
write this,
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
and for better practice always write this,
-(void) btnSubImageClicked:(id)sender{}
I'm coding a custom UINavigationBar. As the app is supposed to work on iOS 4, it isn't possible to use the new customization options available on iOS 5.
That said, I have subclassed my UINavigationBar in order to avoid the Categories which worked very well, as seen on the picture below.
The UIBarButtonItems don't work as well.
I've tried subclassing the UIBarButtonItem class and overriding the drawRect method, but nothing changed.
CustomUIBarButtonItem *backButton = [[CustomUIBarButtonItem alloc] initWithTitle:#"NotÃcias" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
Then I also tried setting the image below, but that also didn't work.
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"noticias_back.png"] style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
So, how am I supposed to do this?
I just do something like...
UIButton *searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
[searchButton setBackgroundImage:[UIImage imageNamed:#"search"] forState:UIControlStateNormal];
[searchButton setBackgroundImage:[UIImage imageNamed:#"search_pressed"] forState:UIControlStateHighlighted];
[searchButton addTarget:self action:#selector(selectedSearch) forControlEvents:UIControlEventTouchUpInside];
[searchButton setImage:[UIImage imageNamed:#"search"] forState:UIControlStateNormal];
[searchButton sizeToFit];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:searchButton];
You have to set the custom buttons before you push it or present it modally. For example:
ENPurchaseEditView *purchaseView = [[ENPurchaseEditView alloc] initWithNibName:#"ENPurchaseEditView" bundle:nil];
// customized left button to cancel - not back.
ENBarButtonImageItem *cancelBtn =
[[ENBarButtonImageItem alloc] initWithFrame:CGRectMake(0, 0, 29, 29)
image:[UIImage imageNamed:#"btn_cancel.png"]
backgroundImage:nil
target:purchaseView
action:#selector(cancel:)];
// setLeftBarButtonItem before you push or present.
// in this view, I also setHidesBackButton = YES in the init so my custom left
// shows up.
[[purchaseView navigationItem] setLeftBarButtonItem:cancelBtn];
[cancelBtn release];
// Edit purchase in full modal view.
// This could be a push - in my case I'm presenting a navController.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:purchaseView];
[[self navigationController] presentModalViewController:navController animated:YES];
In my case, ENBarButtonImageItem is a custom UIBarButtonItem. Here's my class:
#import "ENBarButtonImageItem.h"
#implementation ENBarButtonImageItem
- (id)initWithFrame:(CGRect)frame
image:(UIImage*)image
backgroundImage:(UIImage*)bgImage
{
_button = [UIButton buttonWithType:UIButtonTypeCustom];
[_button setFrame:frame];
self = [super initWithCustomView:_button];
if (self)
{
if (image)
[_button setImage:image forState:UIControlStateNormal];
if (bgImage)
[_button setBackgroundImage:bgImage forState:UIControlStateNormal];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
image:(UIImage*)image
backgroundImage:(UIImage*)bgImage
target:(id)target
action:(SEL)selector
{
self = [self initWithFrame:frame image:image backgroundImage:bgImage];
if (self)
{
[_button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)dealloc
{
[super dealloc];
[_button release];
}
- (void)addTarget:(id)target action:(SEL)selector forControlEvents:(UIControlEvents)controlEvents
{
[_button addTarget:target action:selector forControlEvents:controlEvents];
}
- (void)setImage:(UIImage *)image forState:(UIControlState)state
{
[_button setImage:image forState:state];
}
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state
{
[_button setImage:image forState:state];
}
#end
My custom subclass extend UIControl (EditableImageView)
Basically it contains 3 subviews:
UIButton (UIButtonTypeCustom)
UIImageView
UILabel
All the class works great but now I want to connect some events generated from this class to another. In particular when the button is pressed I want to forward the event to the owner viewcontroller so that I can handle the event. The problem is that I can't figure out how to implement this behaviour.
Within EditableImageView I can catch the touch event using [button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside] but I don't know how to forward it inside of the buttonPressed selector.
I also tried to implement touchesBegan but it seems never called...
I'd like to capture the button press event from the viewcontroller in this way:
- (void)viewDidLoad {
[super viewDidLoad];
self.imageButton = [[EditableImageView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 80.0f, 80.0f)];
[imageButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:imageButton];
[imageButton setEditing:NO];
}
This is my UIControl subclass initialization method:
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor clearColor]];
button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height);
[button setImage:[UIImage imageNamed:#"nene_70x70.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
transparentLabelBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"editLabelBackground.png"]];
transparentLabelBackground.hidden = YES;
[self addSubview:transparentLabelBackground];
// create edit status label
editLabel = [[UILabel alloc] initWithFrame:CGRectZero];
editLabel.hidden = YES;
editLabel.userInteractionEnabled = NO; // without this assignment the button will not be clickable
editLabel.textColor = [UIColor whiteColor];
editLabel.backgroundColor = [UIColor clearColor];
editLabel.textAlignment = UITextAlignmentLeft;
UIFont *labelFont = [UIFont systemFontOfSize:16.0];
editLabel.font = labelFont;
editLabel.text = #"edit";
labelSize = [#"edit" sizeWithFont:labelFont];
[self addSubview:editLabel];
}
return self;
}
Thanks.
I solved in this way:
EditableImageView.h:
#interface EditableImageView : UIControl {
UIButton *button;
UIImageView *transparentLabelBackground;
UILabel *editLabel;
CGSize labelSize;
BOOL editing;
}
#property (nonatomic, retain) UIButton *button;
#property (nonatomic, retain) UILabel *editLabel;
#property (nonatomic, retain) UIImageView *transparentLabelBackground;
#property (nonatomic, getter=isEditing) BOOL editing;
- (void)buttonPressed:(id)sender;
#end
EditableImageView.m:
(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor clearColor]];
button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height);
[button setImage:[UIImage imageNamed:#"nene_70x70.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
.......
}
}
- (void)buttonPressed:(id)sender {
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
MyController.m:
- (void)viewDidLoad {
[super viewDidLoad];
self.imageButton = [[EditableImageView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 80.0f, 80.0f)];
[imageButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:imageButton];
}
- (void)buttonPressed:(id)sender {
NSLog(#"buttonPressed!");
}