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.
Related
I am trying to use invocation to callback a UIView in Objective C and toggle its hidden property. The message must be sent to a custom view in a dedicated class SquareView.
For demonstration purposes my invokerMethod will be called from a UIButton. The appropriate place for this and the SquareView property would seem to be the UIViewController. But I can’t tell whether invocation is meant to return a value and my sample code gives the following error
+[NSInvocation _invocationWithMethodSignature:frame:]: method signature argument cannot be nil'
Can someone please point out what I have got wrong. The examples of NSInvocation I’ve looked at here here and here have so far not shed any light on this. And this link is dead.
EDIT
This may be a duplicate question but the answer did not fix my problem. But I found another question on invocation with answers that helped produce a simpler version of what I am trying to do, with a slightly different problem related to the one here in this post.
Here is my code so far
ViewController.h
#import <UIKit/UIKit.h>
#import "SquareView.h"
#interface ViewController : UIViewController
#property (nonatomic, weak) UIView* square;
#end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
SquareView *square = [[SquareView alloc] initWithFrame:CGRectMake(60, 60, 100, 100)];
[self.view addSubview:square]; // draw once only
[self.view addSubview:[self button:CGRectMake(120, 230, 100, 50)]];
SEL selector = #selector(invokerMethod:);
BOOL toggle;
UIView *target = _square;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
invocation.selector = selector;
invocation.target = target;
[invocation setArgument:&toggle atIndex:2];
[invocation invoke];
__weak id returnValue = nil;
[invocation getReturnValue:&returnValue];
}
Here is the invoker method …
- (id)invokerMethod:(NSInteger)tag
{
NSLog(#"toggle view each time”);
if (_square)
{
if (_square.hidden)
{
[_square setHidden:NO];
}
else
{
[_square setHidden:YES];
}
}
return nil;
}
… and here is the button method …
- (UIButton *)button:(CGRect)box
{
UIButton *tap = [[UIButton alloc] initWithFrame:box];
tap.backgroundColor = [UIColor lightGrayColor];
[tap setTitle:#“toggle" forState:UIControlStateNormal];
[tap addTarget:self action:#selector(invokerMethod) forControlEvents:UIControlEventTouchUpInside];
return tap;
}
… and here is the view that gets toggled.
SquareView.h
#import <UIKit/UIKit.h>
#interface SquareView : UIView
#end
SquareView.m
#import "SquareView.h"
#implementation SquareView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
UIView *square = [[UIView alloc] initWithFrame:frame];
square.backgroundColor = [UIColor redColor];
[self addSubview:square];
}
return self;
}
#end
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.
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"];