I'm pretty new to objective c and iOS development, and I feel sometimes like I'm banging my head into a brick wall...
I'm adding an image programmatically to the screen to server as a menu button. I have a class handling that button. This is the .h file:
#import <Foundation/Foundation.h>
#interface MenuButton : NSObject <UIGestureRecognizerDelegate>
#property UIImageView * menuButton;
- (id) initWithButton: (UIImageView *) mb;
- (void) onTapMenuButton;
#end
And this is the .m file:
#import "MenuButton.h"
#implementation MenuButton
- (id) initWithButton: (UIImageView *) mb {
self = [super init];
if(self) {
self.menuButton = mb;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onTapMenuButton)];
tap.numberOfTapsRequired = 1;
[self.menuButton addGestureRecognizer:tap];
tap.delegate = self;
}
return self;
}
- (void) onTapMenuButton {
NSLog(#"SUCCESS!");
}
#end
Whenever I tap the button, the program stops running. In the output window all I can see is some text: "(lldb)", and the editor shows me the main function, highlighting the only line I have there, which I haven't touched at all (the one created automatically when I start a single-view application).
What am I doing wrong?
I suspect that you're creating a MenuButton instance, which sets up this tap gesture recognizer, but you're not retaining the the MenuButton instance and it becomes deallocated. The result: the tap gesture recognize is calling onTapMenuButton on an object that no longer exists.
How are you keeping hold of the MenuButton objects?
Related
I am using Parse anypic tutorial and I want to create a somehow different UI. But I have some troubles.
So, my ViewController is this :
#interface PAPHomeViewController ()
#property (nonatomic, strong) PAPSettingsActionSheetDelegate *settingsActionSheetDelegate;
#property (nonatomic, strong) UIView *blankTimelineView;
#end
#implementation PAPHomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"LoadView is called");
// Present Anypic UI
[self presentUI];
}
-(void) presentUI {
/*UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[backgroundImageView setImage:[UIImage imageNamed:#"DefaultAnypic.png"]];
self.view = backgroundImageView;*/
// Settings button
self.settingsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.settingsButton addTarget:self
action:#selector(settingsButtonAction:)
forControlEvents:UIControlEventTouchUpInside];
[self.settingsButton setTitle:#"Settings" forState:UIControlStateNormal];
self.settingsButton.frame = CGRectMake(200.0, 200.0, 100.0, 100.0);
[self.view addSubview:self.settingsButton];
}
and its .h file is this :
#interface PAPHomeViewController : PAPPhotoTimelineViewController
#end
The PAPPhotoTimelineViewController is also a separateViewController, which the Home extends from and it is a tableViewController, which also calls ViewDidLoad.
The problem :
With the above Code, I see my button and I can click on my button.
But, if I uncomment stuff for the background, I do see the background, I do see the button, but it cannot be clicked - it is like no touch on the button is identified.
I am also confused, now that I am extending another ViewController which also implements viewDidLoad, why they are both called, in which order etc.
You shouldn't assign a new UIView to your self.view.
Instead of self.view = backgroundImageView;, just add it like a random view.
[self.view addSubview:backgroundImageView];
Doing that, you will follow the right way to add subview: your backgroundImageView will be displayed in your view, and your button will be add above it.
I am creating UIViewController programmatically. In its viewDidLoad, I am creating instance of custom UIView Component which has bunch of button and text filed. I set this view as viewControllers view.
But when I select any UIButton it does not fire any event or tapping inside UITextFiled does not bring up keyboard either.
- (void)viewDidLoad
{
[super viewDidLoad];
SomeView *sv = [[SomeView alloc] initWithFrame:self.view.bounds];
self.view.userInteractionEnabled = YES;
self.view = sv;
//[self.view addSubView:sv];
self.title = #"Something";
}
Is there anything wrong with this piece of code ? Even adding subivew does not work.
I added tapgesture to sv and It was getting detected but nothing else was getting selected on view.
I tried added buttons/textfiled to the viewcontrollers view directly. Then it works but not through customview component.
Try holding a strong reference to the view, It might be getting deallocated.
#interface YOURCLASS ()
#property (nonatomic, strong) SomeView *sv;
#end
And then Go back fro trying to add it as a subview. See if that works.
- (void)viewDidLoad
{
[super viewDidLoad];
self.sv = [[SomeView alloc] initWithFrame:self.view.bounds];
self.view.userInteractionEnabled = YES;
[self.view addSubView:self.sv];
self.title = #"Something";
}
Can anyone help me to understand what is going wrong with my function below pls?
I'm fairly new to native IOS dev.
I wanted to implement a side panel into our app using this tutorial (http://www.appcoda.com/ios-programming-sidebar-navigation-menu/).
All that works fine and is straightforward enough - but I wanted to trigger the reveal functionality via a standard button rather than a dynamic button in the header - to suit our design..
The original code is as follows -
#import "SWRevealViewController.h"
// Change button color
_sidebarButton.tintColor = [UIColor colorWithWhite:0.96f alpha:0.2f];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
to replicate that functionality triggered by a button I added the following to the .h file -
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
#property (weak, nonatomic) IBOutlet UIButton *revealLeftBtn;
- (IBAction)btnClickRevealL:(id)sender;
and the following in my .m file
- (IBAction)btnClickRevealL:(id)sender {
[self.revealViewController];
[#selector(revealToggle:)];
}
I get the error 'suspected identifier' for the above lines - I dont understand how the functions triggered with the previous method and not with the above - can anyone help?
Cheers
for reference this is the entire .M file -
#import "MainViewController.h"
#import "SWRevealViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"";
// Change button color
_sidebarButton.tintColor = [UIColor colorWithWhite:0.96f alpha:0.2f];
[self.navigationController.navigationBar setTranslucent:TRUE];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnClickRevealL:(id)sender {
[self.revealViewController];
[#selector(revealToggle:)];
}
#end
This line:
(IBAction)btnClickRevealL:(id)sender {
[self.revealViewController];
[#selector(revealToggle:)];
}
Does nothing.
I guess this is what you want to do:
[self.revealViewController revealToggle:sender];
When you set the target and the action of a button, you set which class is doing the action (target) and what method is called (action).
that's the equivalent of doing [target action]
- (IBAction)logInBtnClicked:(id)sender {
//Remove WhiteSpace from start of uitextfield
self.emailIdTxtFldRef.text = [self.emailIdTxtFldRef.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
self.passwordTxtFldRef.text = [self.passwordTxtFldRef.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
if ([self.emailIdTxtFldRef.text isEqualToString:#""]||[self.passwordTxtFldRef.text isEqualToString:#""]) {
[self showMessage:#"All fields are mandatory" withTitle:#"Error"];
}else{
SWRevealViewController *revealVC = [self.storyboard instantiateViewControllerWithIdentifier:#"swRevealViewContoller"];
revealVC.delegate=self;
[[UIApplication sharedApplication]keyWindow].rootViewController = revealVC;
}
}
Basically, I have a UIViewController with a xib built for holding content in a UIScrollView. this gets populated from an RSS feed. this works as expected. I want a tap on the UIView that the view controller owns to respond to a tap and continue on its way. however, a tap crashes the app with the "unrecognized selector sent to instance" error. I really have no clue what's going on.
The .h file of the xib's view controller looks like this:
#property (nonatomic,retain) IBOutlet UIImageView *article_image;
#property (nonatomic,retain) IBOutlet UILabel *article_title;
#property (nonatomic,retain) IBOutlet UILabel *article_date;
#property (nonatomic,retain) IBOutlet UIActivityIndicatorView *spinner;
#property (nonatomic,retain) NSString *preview_image;
- (void) loadPreviewImage;
Then the .m file looks like this:
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGesture)];
singleTap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:singleTap];
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
self.view.layer.shadowOpacity = 0.6;
self.view.layer.shadowRadius = 1.5;
self.view.layer.shadowOffset = CGSizeMake(0, 0);
}
- (void) singleTapGesture:(UITapGestureRecognizer *)gesture {
NSLog(#"TAPPED!");
}
Even if I put just a simple roundrectbutton in the xib and attach it to an IBAction - it crashes, so I'm figuring there's something wrong with how my xib is set up, but I have no clue as to what. those properties in the .h get populated just fine from the VC that holds the scrollview, so the xib obviously knows the file it's associated with, so I just can't figure out why it's crashing and throwing that error on a tap.
The fix is this:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGesture:)];
notice the : at the end of the selector.
Indeed, your action method signature is:
- (void) singleTapGesture:(UITapGestureRecognizer *)gesture;
while
#selector(singleTapGesture)
would rather identify:
- (void) singleTapGesture;
Hope this clarifies the issue.
well, i never really figured out exactly what was causing the crash - so i wound adding the gesture recognizer to the objects into the loop that builds them and all works great. not how i'd like to have done it (was trying to keep it in the object's class definition) but whatever. perhaps this will help someone else.
You can download code example from this libk:
https://github.com/mriddi/ExempleCustomGestureRecognizer.git
I create my cusom gesture recognizer class like this:
#protocol MyGestureRecognizerDelegate <UIGestureRecognizerDelegate>
#optional
-(void) willDo;
#end
#interface MyGestureRecognizer: UIGestureRecognizer
{
…
}
#property (nonatomic, assign) id <MyGestureRecognizerDelegate> delegate;
…
#end
#implementation MyGestureRecognizer
#synthesize delegate;
…
-(void) call{
[delegate willDo];
}
…
#end
My ViewController adopt MyGestureRecognizerDelegate protocol.
In ViewController I create instances of my class:
MyGestureRecognizer * grFerst;
MyGestureRecognizer * grSecond;
grFerst.delegate=self;
grLeft.delegate=self;
[self.view addGestureRecognizer: grFerst];
[self.view addGestureRecognizer: grSecond];
I want to make both gesture recognizers instances to work simultaneously.
I try to add to my ViewController method
shouldRecognizeSimultaneouslyWithGestureRecognizer
but this method never calls, I checked it using NSLog function.
Please help me solve this problem (allow work both gesture recognizers simultaneously).
Maybe you should allocate the Gestures
MyGestureRecognizer * gesture = [[MyGestureRecognizer alloc] initWithTarget:self action:nil];
gesture.delegate = self;
[self.view addGestureRecognizer:gesture];
Or you could use the control wheel as the target and do all your angle calculations in there. Then you delegate back to the mainViewController.