RemoveFromSuperView not working on UIButton - ios

It seems like such a simple thing to remove a button from a view, but it is not working.
MyViewController.h
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
#property (strong, nonatomic, readonly, getter = getMyButton) UIButton* myButton;
- (id) init;
- (id) getMyButton;
#end
MyViewController.m
#import "MyViewController.h"
#interface MyViewController ()
#end
#implementation MyViewController
#synthesize myButton = _myButton;
- (id) init
{
if([super initWithNibName: nil bundle: nil])
{
_myButton = nil;
}
return self;
}
- (id) getMyButton
{
if(!_myButton) _myButton = [self createMyButton];
return _myButton;
}
- (void) viewDidLoad
{
[super viewDidLoad];
UIButton* myButton = self.myButton;
[self.view addSubview: myButton];
}
- (void) didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (UIButton*) createMyButton
{
UIButton *button = [[UIButton alloc] init];
[button setTitle: #"My Button"
forState: UIControlStateNormal];
[button addTarget: self
action: #selector(myAction:)
forControlEvents: UIControlEventTouchUpInside];
button.frame = CGRectMake(10, 10, 100, 40);
return button;
}
- (void) myAction: (id) sender
{
[self.myButton performSelectorOnMainThread: #selector(removeFromSuperview) withObject: nil waitUntilDone: NO];
}
#end
But no luck. Clicking the button simply does nothing.
If it is not a problem of concurrency then maybe it is a memory management problem? Maybe it is just something daft, I don't know.
I tried putting the following line into the myAction method
NSLog(#"Test 1");
if(_startButton.superview) NSLog(#"Test 2");
Only 'Test 1' is logged. Perhaps that is a clue but what I don't know is why the button has no superview when it is added to view and is visible on the screen
Additional information
I don't know, if any of this is relevant, but maybe
I just updated Xcode to the latest version from the developer program (it supported up to iOS version 7.0 before, now 7.1)
I just started testing the app on an actual iPhone (I get the same problem testing with the simulator though)
Around the same time as this problem I also noticed that NSLog function doesn't work inside AppDelegate applicationHasLaunched method
Thanks

You didn't set the action for that button.
Change your createMyButton method like:
- (UIButton*) createMyButton
{
UIButton *button = [[UIButton alloc] init];
[button setTitle: #"My Button"
forState: UIControlStateNormal];
button.frame = CGRectMake(10, 10, 100, 40);
[button addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
return button;
}
Also change myAction method like:
- (void)myAction:(UIButton *)sender
{
[sender performSelectorOnMainThread: #selector(removeFromSuperview) withObject: nil waitUntilDone: NO];
}

Your code seems overly complicated:
Why do you need to lazy create the button?
Why does it need to be readonly?
Why do you need the performselector in your action?
I have taken the liberty to rewrite your code:
Header file
#property (nonatomic,strong) UIButton * button;
Code file
- (void)viewDidLoad
{
[super viewDidLoad];
self.button = [UIButton buttonWithType:UIButtonTypeSystem];
[self.button setTitle:#"MyButton" forState:UIControlStateNormal];
self.button.frame = self.view.bounds;
[self.button addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
}
-(void)myAction:(UIButton*)sender
{
[sender removeFromSuperview];
}
Happy coding!
Edit
If you insist on going with your original code, try changing
- (id) getMyButton
to
-(UIButton*)myButton

Buttons are a class family and should be created with [UIButton buttonWithType:]

I am sure that your myAction is not get fired. Cause you forget to addTarget
on your createMyButton method just add one more line
[button addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventTouchUpInside];

UPDATE: You've also marked this question as iOS but you are importing OSX headers
#import "NSViewController.h"
#interface MyViewController: NSViewController
you should be inheriting from UIViewController
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
Are you creating the view controller via the init code you've posted?
- (id) init
{
if([super initWithNibName: nil bundle: nil])
{
_myButton = nil;
}
return self;
}
Here you are not allocating anything to self the code should be
- (id) init
{
self = [super initWithNibName: nil bundle: nil];
if(self)
{
_myButton = nil;
}
return self;
}

Related

modal UIWebView and camera/image picker issue

I need to upload a local picture in my webview (IOS).
Apparently, it seems that Apple has some problems with that.
2016-04-06 18:47:37.337 DemoWebView[839:112324] Warning: Attempt to
present on whose view is not in the window hierarchy!
(iOS 8 SDK: modal UIWebView and camera/image picker)
Despite my extensive research, I didn't find a solution to my problem.
if anyone can help me .. I would be very grateful.
class : ViewController
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setFrame:CGRectMake(80, 150, 160, 60)];
button.backgroundColor = [UIColor whiteColor];
[button setTitle:#"Click Here !" forState:UIControlStateNormal];
[self.view addSubview:button];
}
-(void) buttonClicked:(UIButton*)sender{
ViewController2 * test = [[ViewController2 alloc]init];
[self presentViewController:test animated:true completion:NULL];
}
#end
class : ViewController2
#interface ViewController2 : UIViewController
#end
#import "ViewController2.h"
#interface ViewController2 ()
#property (strong, nonatomic) UIWebView *webView;
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.view = _webView;
[_webView loadHTMLString:#"<br /><br /><input type=\"file\" accept=\"image/*;capture=camera\">" baseURL:nil];
}
#end
DemoProjet :
Thks
You are trying to present UIWebview indirectly from first ViewController,that's reason you are getting warning message.
Try This:
#import "ViewController2.h"
#interface ViewController2 (){
UIWebView *webView;
}
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
webView = [[UIWebView alloc] init];
[self.view addSubview:webView]
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
webView.frame = [UIScreen mainScreen].bounds;
[_webView loadHTMLString:#"Your_html_string" baseURL:nil];
}
}
#end
update: I saw your question containing link and i found that you didn't override this method
-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
if ( self.presentedViewController)
{
[super dismissViewControllerAnimated:flag completion:completion];
}
}
It works with the override. Thanks a lot for your answer.
EDIT
I understand why it didn't work in the first time i tried.. In my main app, i have a UINavigationController class but i continued to override the dismiss method in my UIViewController class.

How to invoke a method from UIViewController class to Custom UIView class

I am not able to call the method which is written in UIViewController(aViewController) from my custom view bView .
I want to call the method function on my button(btn) click in UIView(bView). But when I click the button, i am getting the following error.
unrecognized selector sent to instance....
Here is my code:
aViewController.h
#import "bView.h"
#import "cViewController.h"
-(void)function;
aViewController.m
-(void)viewDidLoad{
bView = [[bView alloc]init];
[bView makeView];
bView.bViewController = self;
[self.view addSubView:bView];
}
-(void)function{
cViewController *nextViewController = [[cViewController alloc] initWithNibName: nil bundle: nil];
[self.navigationController pushViewController: nextViewController animated: YES];
}
bView.h
#import "bViewController.h"
#interface bView : UIView{
UIButton btn;
bView *BView;
}
-(void)makeView;
-(void)function;
#property (nonatomic,readonly) UIButton *btn;
#property (assign) UIViewController* aViewController;
bView.m
#import "bView.h"
#import "aViewController.h"
#impementation bView
#synthesize btn;
#synthesize aViewController;
-(void)makeView{
btn= [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIImage *btnimg = [UIImage imageNamed:#"btn.png"];
[btn setBackgroundImage:btnimg forState:UIControlStateNormal];
btn.frame = CGRectMake(65, 380, 60, 60);
[self addSubview:btn];
btn.userInteractionEnabled = YES;
[btn addTarget:aViewController action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
How to solve it?
You are setting a target to button in [bView makeView]; method, but at that time bView's aViewController is nil because you are setting it only on the next line. So try this:
-(void)viewDidLoad{
bView = [[bView alloc]init];
bView.bViewController = self;
[bView makeView];
[self.view addSubView:bView];
}
this is how you do it, first off, get rid of the "bView.bViewController = self", it doesn't work that way, you shouldn't do this, ever.
-(void)viewDidLoad {
bView = [[bView alloc]init];
[bView makeView];
[self.view addSubView:bView];
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
function is declared in your UIViewController, not your UIView, so you must call to the button in your viewdidLoad through the bView and then assign it a target and action. I still wouldn't use this method that you are using, but this will do it.
this is the magic:
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
AND, remove these lines from the UIView:
#property (assign) UIViewController* aViewController;
-(void)function;
[btn addTarget:aViewController action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
you should remove these if your intent is for the UIViewController to have the function "-(void)function" and I assume this is what you meant. I'm assuming that your "function" is supposed to be called in your UIViewController
for out purposes here, this:
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
is the same thing as this:
[bView.btn addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
and
bView.btn = #property (nonatomic,readonly) UIButton *btn;
In fact, you don't need to call this button in any UIView, given what you are showing, just call this in your viewDidLoad, like this:
-(void)viewDidLoad
{
[super viewDidLoad];
UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIImage *btnimg = [UIImage imageNamed:#"btn.png"];
[btn setBackgroundImage:btnimg forState:UIControlStateNormal];
btn.frame = CGRectMake(65, 380, 60, 60);
btn.userInteractionEnabled = YES;
[self.view addSubview:btn];
[btn addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
I'm showing you this because you aren't setting up the UIView correctly in the first place by invoking super on it's designated initializer so the best bet now is to just place the button in your viewDidLoad and move on, this is the solution until you understand how the initialize a UIView and set it up correctly. There's a lot of stuff that is wrong with the UIView you have set up and tried to subclass and it's going to be easier for you to just make the button in viewDidLoad and then learn how to subclass correctly in the future.

How to send a value to a ViewController when a button is pressed

I currently have two buttons in my SearchCategoryChooserViewController. What I want to do is to set the chosenCategory property to a certain value depending on which button is pressed, and then send that value over to CriteriaViewController.
I have some psuedo code commented out in my categoryButtonClick function, but I'm not sure how to format the syntax, and where to take it from there. The topCategoryId1 and topCategoryId2 values are coming from SearchViewController. Let me know if you want me to include code from that or any other classes.
SearchCategoryChooserViewController.m:
#import "SearchCategoryChooserViewController.h"
#import "SearchViewController.h"
#import "CriteriaViewController.h"
#interface SearchCategoryChooserViewController ()
#end
#implementation SearchCategoryChooserViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *category1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category1.frame = CGRectMake(10, 120, 300, 35);
[category1 setTitle: [NSString stringWithFormat:#"%#", self.topCategory1] forState:UIControlStateNormal];
[category1 addTarget:self action:#selector(categoryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: category1];
UIButton *category2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category2.frame = CGRectMake(10, 180, 300, 35);
[category2 setTitle: [NSString stringWithFormat:#"%#", self.topCategory2] forState:UIControlStateNormal];
[category2 addTarget:self action:#selector(categoryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: category2];
}
- (IBAction)categoryButtonClick:(id)sender
{
// if (topCategory1 button is pressed) {
// set chosenCategory = self.topCategoryId1
// }
//
// else if (topCategory2 button is pressed) {
// set chosenCategory = self.topCategoryId2
// }
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
// Send the Category Id over to CriteriaViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
CriteriaViewController *controller = (CriteriaViewController *) segue.destinationViewController;
// Send over the search query as well as the specific category to CriteriaVC to use
controller.chosenCategory = self.topCategoryId1;
}
#end
One possible solution would be to use tags. Set each button to have its own tag after creating it, for example:
UIButton *category1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category1.frame = CGRectMake(10, 120, 300, 35);
[category1 setTitle: [NSString stringWithFormat:#"%#", self.topCategory1] forState:UIControlStateNormal];
[category1 addTarget:self action:#selector(categoryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
category1.tag = 1; //added tag to button
[self.view addSubview: category1];
UIButton *category2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category2.frame = CGRectMake(10, 180, 300, 35);
[category2 setTitle: [NSString stringWithFormat:#"%#", self.topCategory2] forState:UIControlStateNormal];
[category2 addTarget:self action:#selector(categoryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
category2.tag = 2; //added tag to button
[self.view addSubview: category2];
Then in your button action method (categoryButtonClick:), check the button's tag like so:
- (IBAction)categoryButtonClick:(id)sender
{ UIButton *button = (UIButton *)sender;
if(button.tag == 1){
chosenCategory = self.topCategoryId1;
}else{
chosenCategory = self.topCategoryId2;
}
}
You could do:
- (IBAction)categoryButtonClick:(id)sender
{
if ([topCategory1 isSelected]) {
set chosenCategory = self.topCategoryId1
}
else if ([topCategory2 isSelected]) {
set chosenCategory = self.topCategoryId2;
}
}
In adition to the #croberth's answer, after conditionally setting chosenCategory, send a performSegueWithIdentifier:sender: message:
- (IBAction)categoryButtonClick:(id)sender
{
UIButton *button = (UIButton *)sender;
if(button.tag == 1) {
chosenCategory = self.topCategoryId1;
}
else {
chosenCategory = self.topCategoryId2;
}
[self performSegueWithIdentifier:#"YOUR_SEGUE_IDENTIFIER" sender:nil];
}
YOUR_SEGUE_IDENTIFIER is the identifier for your segue between the button and the CriteriaViewController. Since your buttons aren't in your storyboard, it should be a segue between the 2 controllers, not from any button.
What you're asking has been answered several times already on SO. You set up a variable in the sending VC in the prepareForSegue method and prepare a variable to receive that value in the receiving VC. Here's an SO link with a lot more detail: ios pass values during a segue to another view

Custom initialization of Subview in iOS gicing error

I am facing problem in custom initialization of my subview class the method somewhat look like this
my sub view .h file lloks like this
#import <UIKit/UIKit.h>
#interface mysubview : UIView
#property(nonatomic,strong)UIButton *mybutton;
#end
ViewController.m file
-(id)initWithbutton:(CGRect)frame color:(UIColor*)mycolor
{
NSLog(#"Into the initializer");
self = [super initWithFrame:frame];
if (self) {
// Initialization code
mybutton = [[UIButton alloc]initWithFrame:CGRectMake(frame.size.width/2,frame.size.height/2,20,20)];
[mybutton setTitle:#"b" forState:UIControlStateNormal];
[mybutton setTitle:#"b" forState:UIControlStateHighlighted];
self.backgroundColor = mycolor;
[self addSubview:mybutton];
}
return self;
}
and in my viewcontroller i am calling it as
p_subview1 = [[mysubview alloc] initWithbutton:CGRectMake(10,10,70,70) color:[UIColor blueColor]];
but during compilation i am getting error no visible interface in my subview class has this method plz consider if i am doing something silly here I am new to iphone development.

selector as parameter in IOS

I want to raise a different method for each created button.
I try to call "FirstImage" method in viewDidLoad but it doesn't work.
I have a problem with the selector in ViewDidLoad. Didn't recognise "FirstImage" which is a void method without parameter.
ViewController.m
- (void)createFirstButton:(NSString *)myName: (SEL *)myAction{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn addTarget:self
action:#selector(myAction)
forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:myName forState:UIControlStateNormal];
btn.frame = CGRectMake(20, 916, 120, 68);
[self.view addSubview:btn];
}
- (void)viewDidLoad{
[self createFirstButton:#"First" myAction:[self FirstImage]];
}
What I have done (I changed "CreateFirstButton" into "CreateButton") :
ViewControler.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myHeight;
#synthesize myWidth;
#synthesize myX;
#synthesize myY;
- (void)createButton:(NSString *)myName:(SEL)myAction:(NSUInteger)my_x:(NSUInteger)my_y:(NSUInteger)my_width:(NSUInteger)my_height
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn addTarget:self
action:myAction
forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:myName forState:UIControlStateNormal];
btn.frame = CGRectMake(my_x, my_y, my_width, my_height);
[self.view addSubview:btn];
}
- (void)myXcrementation{
myX = myX + 150;
}
- (void)viewDidLoad{
myX = 20; myY = 916; myWidth = 120; myHeight = 68;
[self createButton:#"First":#selector(FirstImage):myX:myY:myWidth:myHeight];
[self myXcrementation];
[self createButton:#"Previous":#selector(PreviousImage):myX:myY:myWidth:myHeight];
[self myXcrementation];
[self createButton:#"Pause":#selector(PauseImage):myX:myY:myWidth:myHeight];
[self myXcrementation];
[self createButton:#"Next":#selector(NextImage):myX:myY:myWidth:myHeight];
[self myXcrementation];
[self createButton:#"Last":#selector(LastImage):myX:myY:myWidth:myHeight];
}
- (void)FirstImage{
current = 0;
[self SetImage];
}
-(void)SetImage{
[myImageView setImage: [myArray objectAtIndex:(current)]];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
}
#property(assign, nonatomic) NSUInteger myHeight;
#property(assign, nonatomic) NSUInteger myWidth;
#property(assign, nonatomic) NSUInteger myX;
#property(assign, nonatomic) NSUInteger myY;
#end
I edited this post again and there is no more error.
Special thanks to everybody. It took me time to understand :)
You have to use use #selector as follows
[self createFirstButton:#"First" myAction:#selector(FirstImage)];
Then your signature is wrong, since SEL shouldn't be a pointer.
Change
- (void)createFirstButton:(NSString *)myName: (SEL *)myAction{
to
- (void)createFirstButton:(NSString *)myName: (SEL)myAction{
Finally myAction has type SEL so you can pass it directly to the UIButton method, as follows
[btn addTarget:self
action:myAction
forControlEvents:UIControlEventTouchUpInside];
Also, I'd like to add that using capitalized names for methods it's a very bad practice.
You should use
- (void)viewDidLoad{
[self createFirstButton:#"First" myAction:#selector(FirstImage)];
}
or
- (void)viewDidLoad{
[self createFirstButton:#"First" myAction:NSSelectorFromString(#"FirstImage")];
}
#selector(myAction) should be replaced with myAction, and (SEL *) should be replaced with SEL.
In your code, before -createFirstButton:myAction: is called, its second parameter [self FirstImage] would be evaluated(called) first. #selector() takes a name and returns a SEL.
Change the method literal as in the following
- (void)createFirstButton: (NSString *)myName withAction: (SEL)myAction
For both declaration and definition.
And also why have you declared the same method as a public as well as private?
Use
[self createFirstButton:#"First" withAction:NSSelectorFromString(#"FirstImage")];
And change the method name as :
- (void)createFirstButton:(NSString *)myName: withAction: (SEL) myAction{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn addTarget:self
action:myAction
forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:myName forState:UIControlStateNormal];
btn.frame = CGRectMake(20, 916, 120, 68);
[self.view addSubview:btn];
}
Also,
I wonder-all buttons having same frame, if possible pass frame this method.
If you are looking to pass string as method name to selector, then use NSSelectorFromString. String should end with ':' Example-
NSString *myName=#"aMethod:";
[button addTarget:self
action:NSSelectorFromString(myName)
forControlEvents:UIControlEventTouchDown];

Resources