I have a custom class based on UIButton, and I have difficulties calling the custom setter method in this custom class. I will list the codes in these files:
CallMyMethod.h (subclass of UIButton)
CallMyMethod.m
CallOtherClassMethod.h (to call setter method in CallMyMethod)
CallOtherClassMethod.m
CallMyMethod.h
#interface CallMyMethod : UIButton
#property (nonatomic, setter=setIsSelected:) BOOL isSelected;
#property (nonatomic, retain) UIImageView *checkmarkImageView;
- (void)setIsSelected:(BOOL)aIsSelected; //this is unnecessary, I guess
#end
CallMyMethod.m
#implementation CallMyMethod
#synthesize isSelected = _isSelected;
#synthesize checkmarkImageView = _checkmarkImageView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self loadView];
}
return self;
}
- (void) loadView
{
[self.checkmarkImageView setHidden:YES];
}
- (UIImageView *)checkmarkImageView
{
if (_checkmarkImageView == nil) {
UIImage *checkmarkImage = [UIImage imageNamed:#"checkmark.png"];
_checkmarkImageView = [[UIImageView alloc]initWithImage:checkmarkImage];
[_checkmarkImageView setFrame:CGRectMake(10, 10, 32, 32)];
[self addSubview:_checkmarkImageView];
}
return _checkmarkImageView;
}
- (void)setIsSelected:(BOOL)aIsSelected
{
_isSelected = aIsSelected;
[self.checkmarkImageView setHidden:!_isSelected];
[self addSubview:_checkmarkImageView];
}
#end
CallOtherClassMethod.h
#class CallMyMethod;
#interface CallOtherClassMethod : UIViewController
#property (nonatomic,retain) CallMyMethod *btnCMM;
#end
CallOtherClassMethod.m
#import "CallMyMethod.h"
#implementation CallOtherClassMethod
#synthesize btnCMM;
- (void)viewDidLoad
{
[super viewDidLoad];
self.btnCMM = [[CallMyMethod alloc]initWithFrame:CGRectMake(0, 30, 50, 70)];
//somewhere in my code I will add btnCMM to the view
[someView bringSubviewToFront: btnCMM];
[someView addSubview: btnCMM];
}
//somewhere where I pressed a button to trigger this method
- (IBAction) pressMe:(id)sender
{
NSLog(#"self.btnCMM %#", self.btnCMM); //returned as btnCMM is nil ?!
[self.btnCMM setIsSelected:YES];
}
#end
The issue lies in the program not able to run the codes in setIsSelected method, I have traced btnCMM to be nil in NSLog. I wonder why is this so, because when I call CallOtherClassMethod as a UIViewController, the viewDidLoad would have initialised my custom button. Am I doing something wrong here?
Why not override setSelected, which is a method on UIButton and then use button.selected = YES?
If you want to debug why your button becomes nil, implement dealloc in your UIButton subclass, put a breakpoint there, and see the stack trace to find the reason.
Related
I have tried modify my code many times, but still can't pass variable from UIViewController to UIView, variable always return (null).
// BPGraphView.h
#interface BPGraphView : UIView
#property (nonatomic, retain) NSString *test;
#end
// BPGraphView.m
#import "BPGraphView.h"
#implementation BPGraphView
#synthesize test;
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
NSLog(#"test %#",test);
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"draw %#", test); // always return (null)
if ([test isEqual:#"something"]) {
[self drawOutLine];
}
}
#end
// BloodPressureViewController.m
- (void)viewDidLoad
{
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"something";
}
In your code:
- (void)viewDidLoad
{
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"dd";
}
The variable graphview is basically destroyed once the viewDidLoad is run to finish. It will never get a chance to run drawRect.
Now the question is how should you define a instance variable of BPGraphView in your UIViewController. The easiest way should be adding a BPGraphView onto your view's xib file and link to an IBOutlet in your UIViewController. In this way, you should be able to assign to test
#IBOutlet BPGraphView graphview;
- (void)viewDidLoad
{
graphview.test = #"dd";
}
Without setting a frame, drawRect will not be called.
BPGraphView * graphview=[[BPGraphView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
graphview.test = #"something";
[self.view addSubview:graphview];
I tried this,it works well,in your code,drawRect is not called
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"dd";
[graphview drawRect:CGRectMake(0, 0, 0, 0)];
This is firstPopoverViewController.h code:
#import <UIKit/UIKit.h>
#interface firstPopoverViewController : UIViewController
#end
This is my firstPopoverViewController.m code:
#import "firstPopoverViewController.h"
#interface firstPopoverViewController ()
#end
#implementation firstPopoverViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.contentSizeForViewInPopover = CGSizeMake(300, 290);
// Header label
UILabel *h1 = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 85)];
h1.font = [UIFont fontWithName:#"myFont" size:22.0];
h1.textColor = [UIColor blackColor];
h1.textAlignment = NSTextAlignmentCenter;
h1.text = #"Heading";
h1.numberOfLines = 0;
h1.backgroundColor = [UIColor greenColor];
// Ok button BG View
UIView *buttonBG = [[UIView alloc] initWithFrame:CGRectMake(0, 300-75, 300, 75)];
buttonBG.backgroundColor = [UIColor greenColor];
// Ok button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(300/2-130/2, 290-35-15, 130, 35);
button.backgroundColor = [UIColor whiteColor];
[button setTitle:#"OK" forState:UIControlStateNormal];
[button addTarget:self action:#selector(closePop) forControlEvents:UIControlEventTouchUpInside];
button.adjustsImageWhenHighlighted=YES;
// Adding views
[self.view addSubview:h1];
[self.view addSubview:buttonBG];
[self.view addSubview:button];
}
-(void)closePop {
}
#end
Then there's ViewController.h:
#import <UIKit/UIKit.h>
#import "firstPopoverViewController.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) UIButton *popButton;
#property (strong, nonatomic) firstPopoverViewController *firstPopoverViewController;
#property (strong, nonatomic) UIPopoverController *firstPopover;
#end
And finally ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/* ##### UIPopController stuff ##### */
UIImage *popButtonImage = [UIImage imageNamed:#"menu.png"];
_popButton = [UIButton buttonWithType:UIButtonTypeCustom];
_popButton.frame = CGRectMake(0, 0, 73, 66);
[_popButton addTarget:self action:#selector(openPop) forControlEvents:UIControlEventTouchUpInside];
_popButton.adjustsImageWhenHighlighted=NO;
[_popButton setImage:popButtonImage forState:UIControlStateNormal];
[self.view addSubview:_popButton];
}
-(void)openPop {
if (_firstPopoverViewController == nil) {
//Create the _firstPopoverViewController.
_firstPopoverViewController = [[firstPopoverViewController alloc] init];
}
if (_firstPopover == nil) {
_firstPopover = [[UIPopoverController alloc] initWithContentViewController:_firstPopoverViewController];
_firstPopover.popoverContentSize = CGSizeMake(300, 290);
[_firstPopover presentPopoverFromRect:CGRectMake(0,0, 73, 66) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
NSLog(#"show");
} else {
NSLog(#"dismiss");
[_firstPopover dismissPopoverAnimated:YES];
_firstPopover = nil;
}
}
#end
It's pretty basic code that displays a button and when I click this button it shows popover. I want to close this popover using button that's inside firstPopoverViewControll.m file. There's a closePop{} method, what should I put inside it to close this popover? Thanks.
By the way I'm beginner as you can see, I researched stackoverflow and there are some solutions with delegates, which seems to be working for others, but didn't work for me, could you please show me a solution on my code that I posted? Thank you people very much.
There may be a simpler method that I'm not aware of, but the following method should work:
Use NSNotificationCenter to post a notification back to the ViewController containing the UIPopOverController to tell it to dismiss the popover.
First, in ViewController.m viewDidLoad add:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(closePop:) name:#"ClosePopOver" object:nil];
Then add the following method to ViewController.m:
- (void)closePop:(NSNotification *)notification {
[_firstPopover dismissPopoverAnimated:YES];
}
Then in irstPopoverViewController.m:
- (void)closePop {
[[NSNotificationCenter defaultCenter] postNotificationName:#"ClosePopOver" object:nil];
}
That should do the trick.
A delegate is the way to go. I do admit though that I was confused by them at first, but they are quite simple to setup.
In your firstPopoverController.h put this:
#import <UIKit/UIKit.h>
#protocol FirstPopoverDelegate
- (void) closedPopover;
#end
#interface firstPopoverViewController : UIViewController
#property (nonatomic, assign) id< FirstPopoverDelegate > delegate;
#end
Then in your .m of you popover,
-(void)closePop
{
[self.delegate closedPopover];
}
In your main UIViewController's .h:
#import <UIKit/UIKit.h>
#import "firstPopoverViewController.h"
#interface ViewController : UIViewController <FirstPopoverDelegate>
#property (strong, nonatomic) UIButton *popButton;
#property (strong, nonatomic) firstPopoverViewController *firstPopoverViewController;
#property (strong, nonatomic) UIPopoverController *firstPopover;
#end
Then in the .m, first register to listen of the delegate by adding this to your openPop method:
this is important and easy to forget.. nothing will happen if it is not set
_firstPopoverViewController.delegate = self;
Finally, in your .m add the delegate method:
- (void)closedPopover
{
//you can also pass data back in this function, just modify its parameters here and when you define it in the .h of the popover
[_firstPopoverViewController dismissPopoverAnimated:YES];
}
Simple code is here:
Custom MyButton.h
#interface PaiLifeReadingListButton : UIButton
#property (strong, nonatomic) UIImageView *logoImageView;
#end
Custom MyButton.m
#implementation PaiLifeReadingListButton
#synthesize logoImageView = _logoImageView;
-(id)init
{
_logoImageView = [[UIImageView alloc] initWithFrame:CGRectMake(33.0, 20.0, 80.0, 80.0)];
[_logoImageView setImage:[UIImage imageNamed:#"pic"]];
[self addSubview: _logoImageView];
}
#end
Custom MyView.h:
#property (strong, nonatomic) Mybutton *mybutton;
Custom MyView.m:
-(id) init
{
myButton = [[MyButton alloc] init];
[self addSubview:myButton];
}
ViewController.m:
#synthesize myView;
- (void)viewDidLoad
{
myView = [[Myview alloc] init];
[myView.myButton addTarget:self action:#selector(pressed:) forControlEvents:UIControlEventTouchDown];
self.view = myView;
}
-(void)pressed : (MyButton *)button
{
UIImageView *newImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"other-pic"] highlightedImage:nil];
myView.myButton.logImageView = newImageView;
[self.view setNeedsDisplay]; //----this does not work
}
When I press the button, the imageview does not change. How can I fix this?
Thank you very much!
First thing , you don't need setNeedsDisplay here. setNeedsDisplay is used for redrawing the view (it internally calls the drawRect: method of the view if required) which is not what you want.
Second, you have given the class of your button as MyButton,but in the actual .h and .m files, it is given as #interface PaiLifeReadingListButton and #implementation PaiLifeReadingListButton respectively.
Another thing, the view and button is not initialized with a frame. But I assume you have done that already, since your only problem is the image view not changing.
In your code in pressed method you should change views in the hierarchy, but you change only the object member. You can do something like
myView.myButton.logImageView.image = [UIImage imageNamed:#"other-pic"];
I have a view controller (UserLogin) that calls a method in NSObject class (custompop). The method returns a UIView object to viewController. In method i add one button and call action popupAction on button click. The popupAction calls method in view controller. I set all the delegate property.
Here is the code:
//**in viewcontroller.h**
#import "custompopup.h"
#interface UserLogin : UIViewController<customPopUpDelegate>
{
custompopup *obj_custompopup;//NSObject Class
}
-(void)handlePopUpAction;
//**in viewcontroller.m**
- (void)viewDidLoad
{
[super viewDidLoad];
obj_custompopup = [[custompopup alloc] init];
[obj_custompopup setDelegate:self];
popupview = [[UIView alloc] init];
popupview = [obj_custompopup initwithTitleText:#"Title" withdelegate:self];
[self.view addSubview:popupview];
}
-(void)handlePopUpAction
{
NSLog(#"Inside handlePopUpAction");
}
//**in NSObject.h**
#protocol customPopUpDelegate <NSObject>
-(void)handlePopUpAction;
#end
#interface custompopup : NSObject
{
id<customPopUpDelegate>delegate;
UIButton *First_Btn;
}
#property(retain)id delegate;
//**in NSObject.m**
#synthesize delegate;
-(UIView *)initwithTitleText:(NSString *)titleText withdelegate:(id)del
//returns uiview to viewcontroller
{
self.delegate =del;
UIView *customView = [[UIView alloc] init];
customView.frame = CGRectMake(200, 100, 617,367);
First_Btn =[UIButton buttonWithType:UIButtonTypeRoundedRect];
First_Btn.frame=CGRectMake(20, 330,125,45);
[First_Btn #"title" forState:UIControlStateNormal];
[First_Btn addTarget:self action:#selector(popUpAction) forControlEvents:UIControlEventTouchUpInside];
[customView addSubview:First_Btn];
return customView;
}
-(void)popUpAction
{
[[self delegate] handlePopUpAction];
}
Problem is compiler goes in each method successfully and print everything in console till last step. After complete last step in view controller, EXC_BAD_ACCESS comes and the application crashes.
your init is wrong .. dont get what you try to do but you return customView , leaving self unretained but you are using self.
I have a UIViewController class in which im trying to allocate a UIButton Class. Here is a sample code.
MyViewController.m
- (void)viewDidLoad
{
CGRect frame = CGRectMake(companybuttonxOffset, companybuttonyOffset, buttonWidth, buttonHeight);
CustomButton *customButton = [[CustomButton alloc]initWithFrame:frame];
[self.view addSubview:customButton];
[super viewDidLoad];
}
CustomButton.h
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton {
}
#property (nonatomic, assign) NSInteger toggle;
- (void)buttonPressed: (id)sender;
#end
CustomButton.m
#import "CustomButton.h"
#implementation CustomButton
#synthesize toggle;
- (id) initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//custom button code
[self addTarget: self action: #selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
}
return self;
}
- (void)buttonPressed: (id)sender
{
NSLog(#"buttonPressed !!!!!");
}
#end
Although the button is present in my viewcontroller, if i press the button, i keep getting this error - -[UIButton buttonPressed:]: unrecognized selector sent to instance 0xb1dca50
From what i understand after searching for a lot for an answer is that, initWithFrame never gets called when you subclass the button in IB. Instead i should use initWithCoder. Is this right ? If this is it, then i have no idea what NSCoder is, and how i can use it.
Im tired of searching for a solution for this, please help me out guys.
I guess that in the IB, you have not changed your button's class to CustomButton.
Therefore, it is still a UIButton.
Nonetheless, I back rdelmar here that this is not a very good design.
Your view controller should handle the event, not the button itself.
While I agree you should usually have all targets be in the controller layer, give this a try:
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super initWithCoder:coder])
{
[self customButtonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self customButtonInit];
}
return self;
}
- (void)customButtonInit
{
[self addTarget: self action: #selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
}