Ok, so till now i have been declaring all my view objects in .h file. For e.g:
UIButton *btnCustomFacebookLogin;
And define in my .m file like:
btnCustomFacebookLogin = [UIButton buttonWithType:UIButtonTypeCustom];
btnCustomFacebookLogin.backgroundColor = [UIColor darkGrayColor];
btnCustomFacebookLogin.frame = CGRectMake(0,0,180,40);
btnCustomFacebookLogin.center = CGPointMake(self.view.center.x, 200);
[btnCustomFacebookLogin setTitle: #"Facebook Login" forState: UIControlStateNormal];
[btnCustomFacebookLogin addTarget:self action:#selector(facebookLoginButtonClicked) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview:btnCustomFacebookLogin];
And i have a few more buttons in my app which are all defined in my
- (void)viewDidLoad
I got this checked from my mentor and he told me that all these buttons should be in a separate method and not in viewDidLoad, i have no idea where they should be, i went through some sample codes on the internet and could not find a clue. What is the proper place where all the buttons are defined ? Since i work for a company now i have to follow what conventions are told to me.
Keep your IBOutlets properties outside of header file (*.h) and declare them inside implementation file (*.m) in interface extension of your View Controller.
In your implementation file (*.m) :
#interface MyViewController ()
#property (nonatomic, weak) IBOutlet UIButton *myButton;
#end
Remember to set your property behaviour nonatomic as by default each property gets atomic behaviour and when using UI objects there is no need to make them thread safe. Set it to weakas you are not a direct owner of the object, its lifecycle belongs to your storyboard (assuming you use storyboard).
Meet Doshi is correct about using viewDidLoad and performing selector from inside it, to make an initial setup for your UI elements. It makes your code clear and readable.
I would possibly call it:
- (void)styleUI {
//insert your code here
}
If you find yourself to set specific UIButton styling in different View Controllers in this same way, then to avoid boilerplate code you could create own Class Category for UIButton and specify this same style in one place.
Create a new file selecting Objective-C File.
In File type prefix for your project with name for class (example:
MAPStyling).
Select Category for File Type.
Select Class that you want to create a category for (for UIButton select UIButton).
Inside you category class in implementation file (*.m) add method for your styling:
- (void)map_applyFacebookStyle
// insert your code here but instead to name of your button refer to self.
self.title = #"Facebook Login";
}
Expose method in header file of your category by adding method signature into #interface section.
#interface UIButton (MAPStylig)
- (void)map_applyFacebookStyle;
#end
In your View Controller implementation file (*.m) import your Class Category and modify your method:
- (void)styleUI {
[btnCustomFacebookLogin map_applyFacebookStyle];
}
This will call #selector of your styling method from your Class Category on your UIButton. As you can imagine in this way you can remove a lot of boilerplate code from every View Controller in your application.
Your mentor says, "All these buttons should be in a separate method and not in viewDidLoad". Means you are setting frames and properties to all buttons into viewDidLoad method. He didn't said that you can't define all objects into .h file. So he says, you have do that into other method. Just use following code.
I think, right now you did this:-
- (void)viewDidLoad
{
btnCustomFacebookLogin = [UIButton buttonWithType:UIButtonTypeCustom];
btnCustomFacebookLogin.backgroundColor = [UIColor darkGrayColor];
btnCustomFacebookLogin.frame = CGRectMake(0,0,180,40);
btnCustomFacebookLogin.center = CGPointMake(self.view.center.x, 200);
[btnCustomFacebookLogin setTitle: #"Facebook Login" forState: UIControlStateNormal];
[btnCustomFacebookLogin addTarget:self action:#selector(facebookLoginButtonClicked) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview:btnCustomFacebookLogin];
}
So, just put this code into one method and call this method from viewDidLoad like this:-
- (void)viewDidLoad
{
[self settingPropertiesOfButtons];
}
- (void)settingPropertiesOfButtons
{
//insert your code here..
btnCustomFacebookLogin = [UIButton buttonWithType:UIButtonTypeCustom];
btnCustomFacebookLogin.backgroundColor = [UIColor darkGrayColor];
btnCustomFacebookLogin.frame = CGRectMake(0,0,180,40);
btnCustomFacebookLogin.center = CGPointMake(self.view.center.x, 200);
[btnCustomFacebookLogin setTitle: #"Facebook Login" forState: UIControlStateNormal];
[btnCustomFacebookLogin addTarget:self action:#selector(facebookLoginButtonClicked) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview:btnCustomFacebookLogin];
}
That's it. If you could framing those buttons in .storyboard file or in .xib, then its better.
Related
I have a UIButton. I bound a target as follows.
[button addTarget:self action:#selector(myFunction)
forControlEvents:UIControlEventTouchUpInside];
When i click my Button multiple times quickly it invoke the target function multiple times.
On Tapping button i present a new View controller.
when i click 3 times quickly then my new view controller is shown 3 times.
This is something stupid. Whats the point of triggering the function again once the View has been shifted to a new View controller. Why the Hell Apple do such stupid things ?
Any Help please?
First of all its not apple bugs. It should be handle manually. So follow these step
First make your global instance of your button then do this
.h file
#property (weak, nonatomic) IBOutlet UIButton *btn;
.m file
- (IBAction)myFunction:(id)sender
{
self.btn.userInteractionEnabled = NO;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.btn.userInteractionEnabled = YES;
}
Take one global bool flag like "isItDone" or it declare in singleton class.
in "myFunction" set it as false
which View controller you push on that function in that class's "ViewDidAppear" method set as true.
it will help you.
I have same problem and it is good solution for that to manage it using one global variable.
I think this will help you.
Change your calling function like this
- (IBAction)myFunction:(id)sender
{
UIButton *button = (UIButton*)sender;
button.userInteractionEnabled = NO;
}
and call your function like this
[button addTarget:self action:#selector(myFunction:)
forControlEvents:UIControlEventTouchUpInside];
if you want to store the selection incase you came back to the view controller then only you need to keep a boolean flag to store if its clicked once or not.
Set the IBOutlet to your button, in the viewWillAppear method write,
button.userInteractionEnabled = YES;
and when you click on the button set,
button.userInteractionEnabled = NO;
I'm implementing a function to create a custom UIAlertView. I have extended UIView with a category, and I'm creating my method, called
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
I want to add a selector to a button inside my custom alertview, but this selector is contained in my UIViewController. Should I move the selector into the category, or somehow reference it in the viewcontroller? And If I move the selector into the category, I won't be able to access the navigationcontroller...
in UIView+Category.m:
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
{
UIView *alert = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width/2)-100, (self.frame.size.height/2)-50, 200, 100)];
UIButton *confirmButton = [[UIButton alloc] initWithFrame:CGRectMake(30,40, 50, 50)];
[confirmButton addTarget:self action:#selector(delete:) forControlEvents:UIControlEventTouchUpInside];
[alert addSubview:confirmButton];
[self addSubview:alert];
}
selector method in MyViewController.m
- (IBAction)delete:(id)sender
{
[[self.view viewWithTag:-7] removeFromSuperview];
self.navigationController.navigationBar.hidden = NO;
}
You are bumping up against the limitations of categories. You can't add instance variables to a class in a category, so you don't have a clean way to save a pointer to your presenting view controller.
I would suggest adding a new method to your category:
- (void) addButtonWithTitle: (NSString*) title
target: (id) target
action: (SEL) action
forControlEvents: (UIControlEvents)controlEvents;
Then in the implementation of that method, use the parameters that are passed in to create and configure the button. The method includes a target, selector, and list of events that should trigger the action.
The selector should be implemented in your viewController , since you could be using your alertView in different viewControllers. Therefore sometimes you would need to perform a logic specific to that viewController. Also MVC 101 forbids you from trying to implement an action in a UIView subclass. Therefore again your viewController should implement the action.
This is what I would use to change the text if it were the same method but I want to change it from a different method.
-(IBAction)StartTimer:(id)sender {
[sender setTitle:#"Stop" forState:UIControlStateNormal];
}
-(IBAction)ResetAllData:(id)sender {
[(NEED THIS PIECE) setTitle:#"Start" forState:UIControlStateNormal];
}
There are several ways of doing it. Perhaps the simplest one is to make an IBOutlet for the other button, give it a name (say, anotherButton), attach it in the storyboard, and call it directly, like this:
-(IBAction)ResetAllData:(id)sender {
[anotherButton setTitle:#"Start" forState:UIControlStateNormal];
}
An alternative would be to add a tag * to the button in question (say, 123), and then reference it by its numeric tag, like this:
-(IBAction)ResetAllData:(id)sender {
[[self viewWithTag:123] setTitle:#"Start" forState:UIControlStateNormal];
}
* To add a tag, select the button in the interface builder, open its properties, find the tag, and type in the desired value in the text field.
Make the UIButton you want to change the title of a property of the class, then you will have direct access to it. For example, the following could be put in your ViewController's .m file.
#interface ViewController ()
#property (nonatomic) UIButton *otherButton;
#end
Then in your first IBAction, just set the title of otherButton.
-(IBAction)ResetAllData:(id)sender {
[self.otherButton setTitle:#"Start" forState:UIControlStateNormal];
}
I am creating an iOS app as defined here! So here in this app I am using a segmented control (Dynamically added) to give the user the choice to select one of the options. When the user selects a choice I want to send a string to selector method, so I wanted to know if we can send anything apart from id and event to an action:#selector that we add.
Here's the code
NSArray *optionsArray =[NSArray arrayWithArray:qna2.answers];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:optionsArray];
segmentedControl.frame = CGRectMake(xOffset,yOffset, 250, 50);
[segmentedControl setSelectedSegmentIndex:UISegmentedControlNoSegment];
[self.view addSubview:segmentedControl];
yOffset+=100;
[segmentedControl addTarget:self action:#selector(MyAction:) forControlEvents: UIControlEventValueChanged];
So can we do like #selector(Myaction: Category) ?
Your best bet is probably to store the string in a property like this:
#property (nonatomic, copy) NSString *myString;
Then, retrieve the value in the myAction: method.
Or you could subclass your control and add a property that way:
#interface MySegmentedControl : UISegmentedControl
#property (nonatomic, copy) NSString *stringProperty;
#end
When you set each segmented control:
MySegmentedControl *segmentedControl = [[MySegmentedControl alloc] initWith...];
segmentedControl.stringProperty = #"Some meaningful value";
[segmentedControl addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventValueChanged];
In the change handler:
- (void) myAction:(MySegmentedControl *)sender
{
NSString *importantString = sender.stringProperty;
// do stuff with importantString
}
My approach would be to subclass UISegmentedControl, say MYUISegementedControl, and create a delegate protocol so that it can call back to your UIViewController.
When you create your MYUISegmentedControl instance you can add whatever additional properties you need and pass this information back to the delegate, or at the very least your delegate can access these properties off the MYUISegmentedControl properties.
You could also use a category rather than a subclass.
I've just started learning the basics of Xcode and Objective C and I am making a basic torch app as a starting point.
I've already picked up most of the basics of things, but I don't know how to make a reference to another element from an separate action (I have no idea if this terminology is correct).
For example:
- (IBAction)screenButtonClicked:(id)sender {
UIButton *button = (UIButton *)sender;
if (_ScreenOnOff) {
[self.view setBackgroundColor:[UIColor blackColor]];
[button setTitle:#"Screen (Off)" forState: UIControlStateNormal];
}
else {
[self.view setBackgroundColor:[UIColor whiteColor]];
[button setTitle:#"Screen (On)" forState: UIControlStateNormal];
}
_ScreenOnOff = !_ScreenOnOff;
}
I have a button on the storyboard which is linked to that, and I have a UIImageView which I want to show and hide (depending on the if's).
I've looked everywhere about how to do this and put it as many ways as I can into Google, but no luck.
This might be a baby step in Objective C, but please help as it will teach me.
Thanks in advance.
Declare an IBOutlet for the UIImageView in the header file:
#property (weak) IBOutlet UIImageView *myImageView;
After that, connect the UIImageView to this IBOutlet in Interface Builder.
Then, you can reference (and hide it) like:
self.myImageView.hidden = _ScreenOnOff;
in your implementation file.
See also: Creating and Connecting an Outlet
This action is probably owned by your view controller. If your view controller has a UIImageView property named 'imageView' you can access it from inside your action just like you're doing with the _ScreenOnOff.
To hide your image view you could do something like this:
self.imageView.hidden = YES;
Note that it is important to use self.imageView and self.ScreenOnOff instead of accessing directly the property by _imageView. When you declare a property in your class (be it an IBOutlet or not) the compiler synthesizes accessor methods to that property (get and sets). So when you call self.ScreenOnOff it would be the similar of doing [self ScreenOnOff].
The only places where you will access the property directly by '_' is inside init and dealloc methods. '- (void) viewDidLoad' is on type of init method. I guess you want something like this:
- (IBAction)screenButtonClicked:(id)sender {
UIButton *button = (UIButton *)sender;
if (self.ScreenOnOff) {
[self.view setBackgroundColor:[UIColor blackColor]];
[button setTitle:#"Screen (Off)" forState: UIControlStateNormal];
self.imageView.hidden = YES;
}
else {
[self.view setBackgroundColor:[UIColor whiteColor]];
[button setTitle:#"Screen (On)" forState: UIControlStateNormal];
self.imageView.hidden = NO;
}
self.ScreenOnOff = !self.ScreenOnOff;
}
I hope that helps.