iOS: Instance Values change between method call - ios

I am trying to implement a custom implementation of switching buttons so that only one can be selected at a time. I have run into a weird error where I init an object using [[ajdSwitchButton alloc] init]. In the init I set a class property as follows self.currentSelection = 2.
The issue is that between the init and the first call to an IBAction method, the value is changed to 0. I cannot figure out why. Here is the relevant code:
ajdSwitchButton.h
#import <UIKit/UIKit.h>
#interface ajdSwitchButton : UIView
#property (nonatomic) NSInteger currentSelection;
// Button Outlets
#property (nonatomic, strong) IBOutlet UIButton *buttonOne;
#property (nonatomic, strong) IBOutlet UIButton *buttonTwo;
// Button Actions
- (IBAction)buttonPress:(id)sender;
- (IBAction)buttonPressTwo:(id)sender;
// Instance Methods
- (void)switchButtonState:(UIButton *)button;
#end
ajdSwitchButton.m
#import "ajdSwitchButton.h"
#implementation ajdSwitchButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}
// Handles button press actions for buttonOne
- (IBAction)buttonPress:(id)sender {
NSLog(#"%#", self);
// Y button pressed
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else if (self.currentSelection == 1) {
// No was previously selected
// Unselect NO and select YES
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// Y button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
}
self.currentSelection = 0;
}
- (IBAction)buttonPressTwo:(id)sender {
// N button pressed
NSLog(#"%i", self.currentSelection);
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
} else if (self.currentSelection == 0) {
// Yes was previously selected
// Unselect YES and select NO
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// N button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
}
self.currentSelection = 1;
}
// Switches the look and state of the button
- (void)switchButtonState:(UIButton *)button {
if (!button.selected) {
button.highlighted = YES;
button.selected = YES;
} else {
button.highlighted = NO;
button.selected = NO;
}
}
#end
I link an instance of ajdSwitchButton to an IBOutlet view within ViewController. Any help would be greatly appreciated.
EDIT: I pasted some NSLogs to check the memory value of the object directly after the init and as soon as the IBAction method is called. Here is the before and after:
<ajdSwitchButton: 0x746d2e0; frame = (0 0; 0 0); layer = <CALayer: 0x7472c40>>
<ajdSwitchButton: 0x7471b10; frame = (77 232; 180 83); autoresize = TM+BM; layer = <CALayer: 0x7471bf0>>

IBOutlets init through initWithCoder:(NSCoder)aDecoder, so you need to implement this method.
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}

You are doing it in your code...
That might be a silly mistake or you need that.. please check your code :
- (IBAction)buttonPress:(id)sender {
NSLog(#"%#", self);
// Y button pressed
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else if (self.currentSelection == 1) {
// No was previously selected
// Unselect NO and select YES
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// Y button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
}
/* SEE HERE */
self.currentSelection = 0;
}

The issue is in your question itself.
You are initializing the variable in:
- (id)initWithFrame:(CGRect)frame
{
}
You already mentioned that you are creating the object using [[ajdSwitchButton alloc] init].
You are calling init not initWithFrame so the variable never get initialized.
So implement a function like:
- (id)init
{
self = [super init];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}

Related

Show custom View issue

when I click on button I get only 1 extra view, but I want a the view to be added dynamically on number of click, (like for loop)...Kindly help me with this code, Thanks in Advance,
this is just a part of my code
if (boolVal == true) {
CGRect newFrameC = CGRectMake(_centreView.frame.origin.x, _centreView.frame.origin.y, _centreView.frame.size.width, 50);
CGRect newFrameL1 = CGRectMake(_label2.frame.origin.x, _label2.frame.origin.y+50, _label2.frame.size.width, 50);
_centreView.frame = newFrameC;
_label2.frame = newFrameL1;
boolVal = false;
}else if (boolVal == false){
CGRect newFrameC = CGRectMake(_centreView.frame.origin.x, _centreView.frame.origin.y, _centreView.frame.size.width, 1);
CGRect newFrameL1 = CGRectMake(_label2.frame.origin.x, _label2.frame.origin.y-50, _label2.frame.size.width, 50);
_centreView.frame = newFrameC;
_label2.frame = newFrameL1;
boolVal = true;
}
DummyViewController.m
#import "DummyViewController.h"
#import "ExtraView.h"
#interface DummyViewController ()
#property (nonatomic) unsigned int numberOfExtraViews;
#property (nonatomic, strong) NSMutableArray<ExtraView*>* extraViews;
#property (nonatomic, strong) UILabel* label1;
#property (nonatomic, strong) UILabel* label2;
#end
#implementation DummyViewController
-(void) removeExtraViews{
for (ExtraView* extraView in _extraViews){
[extraView removeFromSuperview];
}
[_extraViews removeAllObjects];
}
-(CGRect) getExtraViewFrame{
CGRect extraViewFrame = _label1.frame;
if (_numberOfExtraViews > 0) {
extraViewFrame = [_extraViews lastObject].frame;
}
extraViewFrame.origin.x += extraViewFrame.size.height;
return extraViewFrame;
}
- (void) addExtraViews{
//[self removeExtraViews];
int numberOfExtraViewsToDraw = _numberOfExtraViews - _extraViews.count;
for (int iterator = 0; iterator < numberOfExtraViewsToDraw; iterator ++){
CGRect extraViewFrame = [self getExtraViewFrame];
ExtraView *extraView = [[ExtraView alloc]initWithFrame:extraViewFrame];
[self.view addSubview:extraView];
[_extraViews addObject:extraView];
}
if (numberOfExtraViewsToDraw > 0) {
CGRect label2Frame = [_extraViews lastObject].frame;
label2Frame.origin.x += label2Frame.size.height;
_label2.frame = label2Frame;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self addExtraViews];
//rest of your code
}
//Use this code in initWithNib/initWithCoder. Don't copy paste the same
-(instancetype)init{
self = [super init];
if (nil != self){
_numberOfExtraViews = 0;
_extraViews = [[NSMutableArray alloc]init];
}
return self;
}
//the function that gets hit when the button is tapped.
- (void) onButtonTap{
_numberOfExtraViews++;
[self.view setNeedsDisplay];
}
Note the following:
I do not understand what the boolVal is, but if it keeps toggling upon the click of the button, you'll never have multiple views.I assumed it toggles, so I havent used it at all.
Use the init code in initWithNib/initWithCoder. Don't copy paste the same. Don't overwrite the given code. Just append to your current init.
In my code onButtonTap is the function that gets hit when the button is tapped.
I've done it by ensuring viewDidLoad method gets hit agin. But I dont think it's necessary. You can also do this:
//the function that gets hit when the button is tapped.
- (void) onButtonTap{
_numberOfExtraViews++;
[self addExtraViews];
}
What has been done:
Let me call what you call as centerView as extraView. There will be many extraViews, so I'll create an array for the same (extraViews).
The count of the number of views is stored in numberOfExtraViews. Initiated to 0 in init.
Whenever the button is tapped, we increase the count and call view's setNeedsDisplay, which in turn hits the viewDidLoad method
In viewDidLoad, we add the extraViews.

iOS Objective-C block callback issue

I am trying to use pure code to create UI practice block pass value between viewController. But the callback block didn't work. The NSLog method didn't print anything on debug area. Here's the code. Give me some tips, thank you.
VC.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (copy, nonatomic) void (^callBack)(NSString *text);
#end
VC.m
- (UITextField *)textField {
if (!_textField) {
_textField = [[UITextField alloc] init];
_textField.backgroundColor = [UIColor whiteColor];
}
return _textField;
}
- (UIButton *)button {
if (!_button) {
_button = [[UIButton alloc] init];
_button.backgroundColor = [UIColor blueColor];
[_button addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
- (void)setupUI {
[self.view addSubview:self.textField];
[self.view addSubview:self.button];
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view.mas_centerX);
make.centerY.mas_equalTo(self.view);
}];
[self.button mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view);
make.centerY.mas_equalTo(self.view).offset(100);
}];
}
- (void)buttonAction {
NSString *str = self.textField.text;
if (self.callBack != nil) {
self.callBack(str);
NSLog(#"This statement didnt print in log");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
}
update code
VC2.m
- (void)viewWillAppear:(BOOL)animated{
self.callBack = ^(NSString *text){
};
}
- (void)buttonAction {
if (self.callBack) {
NSLog(#"It worked on debug area %#", self.textField.text);
self.callBack(self.textField.text);
}
self.textField.text = #"";
}
VC1.m
- (void)viewDidLoad {
[super viewDidLoad];
_secondVc = [[SecondViewController alloc] init];
_secondVc.callBack = ^(NSString *str){
};
[self setupUI];
self.view.backgroundColor = [UIColor greenColor];
}
- (void)viewWillAppear:(BOOL)animated {
if (_secondVc.callBack != nil) {
NSLog(#"It wrked on debug screen");
_secondVc.callBack = ^(NSString *str){
NSLog(#"It didn't worked on debug screen");
//I want set my label.text = str;
};
};
}
The only way is that you property
#property (copy, nonatomic) void (^callBack)(NSString *text);
is empty. Try to put breakpoint in buttonAction method and look at the property.
As Sander and KrishnaCA mentioned your callBack is nil. I would suggest you create a definition of the block like this:
typedef void(^TextBlock)(NSString *text);
Then change your property to:
#property (copy, nonatomic) TextBlock callBack;
Create a copy of the block in your first view controller:
#interface FirstViewController()
#property (copy, nonatomic) TextBlock firstViewControllerCallBack;
#end
Initialize the callback copy (i.e. in viewDidLoad)
- (void)viewDidLoad {
[super viewDidLoad];
self.firstViewControllerCallBack = ^(NSString *text){
NSLog(#"Second view controller's button tapped!");
};
}
Assign the callback to the second view controller right before presenting/pushing it:
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.callBack = self.firstViewControllerCallBack; // Assign the callback
// ... Presenting the view controller
Clean up the completion block after you done with it (i.e. in viewWillDisappear):
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.firstViewControllerCallBack = nil;
}

Custom alert view in iOS issue

In my app I've to create a custom alert view like the following:
So I followed this tutorial to create a custom alert view. I finished it but I'm getting issue in the following method:
- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
NSMutableArray *items = [[NSMutableArray alloc]init];
[items addObject:self.buttonOk];
[items addObject:self.buttonClose];
int buttonIndex = (tag == 1);
if (shouldRemove) {
[items removeObjectAtIndex:buttonIndex];
} else {
if (tag == 1) {
[items insertObject:self.buttonOk atIndex:buttonIndex];
} else {
[items insertObject:self.buttonClose atIndex:buttonIndex];
}
}
}
I edited it than the tutorial because I don't need a UIToolBar for buttons. When I run the app it says me that I can't insert a nil object in an NSMutableArray, but I don't understand what's wrong, I hope you can help me to fix this issue.
UPDATE
Here's all the class code I developed:
#import "CustomAlertViewController.h"
#define ANIMATION_DURATION 0.25
#interface CustomAlertViewController ()
- (IBAction)buttonOk:(UIButton *)sender;
- (IBAction)buttonCancel:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UIButton *buttonClose;
#property (weak, nonatomic) IBOutlet UIButton *buttonOk;
#property (strong, nonatomic) IBOutlet UIView *viewAlert;
-(void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove;
#end
#implementation CustomAlertViewController
- (id)init
{
self = [super init];
if (self) {
[self.viewAlert setFrame:CGRectMake(self.labelAlertView.frame.origin.x,
self.labelAlertView.frame.origin.y,
self.labelAlertView.frame.size.width,
self.viewAlert.frame.size.height)];
[self.buttonOk setTag:1];
[self.buttonClose setTag:0];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)showCustomAlertInView:(UIView *)targetView withMessage:(NSString *)message {
CGFloat statusBarOffset;
if (![[UIApplication sharedApplication] isStatusBarHidden]) {
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
if (statusBarSize.width < statusBarSize.height) {
statusBarOffset = statusBarSize.width;
} else {
statusBarOffset = statusBarSize.height;
}
} else {
statusBarOffset = 0.0;
}
CGFloat width, height, offsetX, offsetY;
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft ||
[[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
width = targetView.frame.size.width;
height = targetView.frame.size.height;
offsetX = 0.0;
offsetY = -statusBarOffset;
}
[self.view setFrame:CGRectMake(targetView.frame.origin.x, targetView.frame.origin.y, width, height)];
[self.view setFrame:CGRectOffset(self.view.frame, offsetX, offsetY)];
[targetView addSubview:self.view];
[self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:ANIMATION_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.viewAlert setFrame:CGRectMake(0.0, 0.0, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView commitAnimations];
[self.labelAlertView setText:#"CIAO"];
}
- (void)removeCustomAlertFromView {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:ANIMATION_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.viewAlert setFrame:CGRectMake(0.0, -self.viewAlert.frame.size.height, self.viewAlert.frame.size.width, self.viewAlert.frame.size.height)];
[UIView commitAnimations];
[self.view performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:ANIMATION_DURATION];
}
- (void)removeCustomAlertFromViewInstantly {
[self.view removeFromSuperview];
}
- (BOOL)isOkayButtonRemoved {
if (self.buttonOk == nil) {
return YES;
} else {
return NO;
}
}
- (BOOL)isCancelButtonRemoved {
if (self.buttonClose == nil) {
return YES;
} else {
return NO;
}
}
- (void)removeOkayButton:(BOOL)shouldRemove {
if ([self isOkayButtonRemoved] != shouldRemove) {
[self addOrRemoveButtonWithTag:1 andActionToPerform:shouldRemove];
}
}
- (void)removeCancelButton:(BOOL)shouldRemove {
if ([self isCancelButtonRemoved] != shouldRemove) {
[self addOrRemoveButtonWithTag:0 andActionToPerform:shouldRemove];
}
}
- (void)addOrRemoveButtonWithTag:(int)tag andActionToPerform:(BOOL)shouldRemove {
NSMutableArray *items = [[NSMutableArray alloc]init];
[items addObject:self.buttonOk];
[items addObject:self.buttonClose];
int buttonIndex = (tag == 1);
if (shouldRemove) {
[items removeObjectAtIndex:buttonIndex];
} else {
if (tag == 1) {
[items insertObject:self.buttonOk atIndex:buttonIndex];
} else {
[items insertObject:self.buttonClose atIndex:buttonIndex];
}
}
}
- (IBAction)buttonOk:(UIButton *)sender {
[self.delegate customAlertOk];
}
- (IBAction)buttonCancel:(UIButton *)sender {
[self.delegate customAlertCancel];
}
#end
UPDATE 2
Code in which I use the CustomAlertView:
#import "PromotionsViewController.h"
#import "CustomAlertViewController.h"
#interface PromotionsViewController () <CustomAlertViewControllerDelegate> {
BOOL isDeletingItem;
}
#property(nonatomic,strong) CustomAlertViewController *customAlert;
- (IBAction)buttonBack:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UIButton *buttonAlert;
- (IBAction)buttonAlert:(UIButton *)sender;
#end
#implementation PromotionsViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.buttonAlert setTitle:self.promotionSelected forState:UIControlStateNormal];
[self.customAlert setDelegate:self];
isDeletingItem = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonBack:(UIButton *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc]init];
[self.customAlert removeOkayButton:NO];
[self.customAlert removeCancelButton:NO];
NSString *message = [NSString stringWithFormat:#"La tua offerta %# del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
[self.customAlert showCustomAlertInView:self.view withMessage:message];
isDeletingItem = YES;
}
- (void)customAlertOk {
if (isDeletingItem) {
[self.customAlert removeCustomAlertFromViewInstantly];
} else {
[self.customAlert removeCustomAlertFromView];
}
}
- (void)customAlertCancel {
[self.customAlert removeCustomAlertFromView];
if (isDeletingItem) {
isDeletingItem = NO;
}
}
#end
Maybe you're calling addOrRemoveButtonWithTag:andActionToPerform: at a time where your UI is not fully created, since UI elements are created asynchronously. So if you call this method, right after custom alert view instanciation, you'll get your crash because the buttons in the view are not created.
To solve this issue, you need to call addOrRemoveButtonWithTag:andActionToPerform: only once your custom alert has been added to the view hierarchy.
EDIT :
With the example code you gave in edit 2, you call these lines :
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc]init];
[self.customAlert removeOkayButton:NO];
[self.customAlert removeCancelButton:NO];
}
but when you have just instantiated CustomAlertViewController, its 2 buttons are not yet created, so I suggest you add 2 properties hasOkButton and hasCancelButton and a new constructor to your custom class like this one :
- (instancetype) initWithOk:(BOOL)OkButton AndCancel:(BOOL) CancelButton
{
if(self = [super init])
{
hasOkButton = OkButton;
hasCancelButton = CancelButton;
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// At this time, the custom UI buttons will be created in the UI view hierarchy
[self removeOkayButton: hasOkButton];
[self removeOkayButton: hasCancelButton];
}
And in the caller you can use the following to display a custom alert View:
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [[CustomAlertViewController alloc] initWithOk:NO AndCancel:NO];
// ...
}
EDIT #2
I tried your solution in a real project, I made it work by using these lines int the caller :
- (IBAction)buttonAlert:(UIButton *)sender {
self.customAlert = [self.storyboard instantiateViewControllerWithIdentifier:#"customAlertView"];
self.customAlert.hasOK = NO;
self.customAlert.hasCancel = YES;
NSString *message = [NSString stringWithFormat:#"La tua offerta %# del 20%% è stata convertita in punti IoSi x10", self.promotionSelected];
[self.customAlert showCustomAlertInView:self.view withMessage:message];
isDeletingItem = YES;
}
In the CustomAlertViewController declare 2 visible properties hasOK and hasCancel in.h.
And modify your .m by adding method :
-(void)viewWillAppear:(BOOL)animated
{
[self removeOkayButton:self.hasOK];
[self removeCancelButton:self.hasCancel];
}
Be sure to modify your storyboard (if eligible) to have the "customAlertView" defined this way :
Don't forget also to bind your UIButton to the controller this can be a mistake too in your implementation :
Hope this will help you :)
I found on the web a tutorial to create custom alert view by using code, if you are interested you can go to this tutorial. I used it for my issue and it worked great! You have to fix a few things, because it uses deprecated command but it's easy to fix it.
If you are interested just take a look about this tutorial. I think you can integrate it in your app and after you can easily use for other stuff if it's necessary. I hope that my answer will help someone.

IBAction disabling not working

If the user keeps clicking on button1 one or two , progress2.progress keeps increasing/decreasing on each click and progress1.progress keeps the same value until the user stops clicking. And in case he will surely lose , if he also keeps clicking nothing happens until he stops clicking. I don't want it to be that way since I want to hide/disable the buttons as soon as it's confirmed that he's losing to fix this issue. Any way to fix that?
Here is my .m :
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (BOOL)prefersStatusBarHidden { return YES; }
- (void)viewDidLoad
{
progress1.progress=arc4random() % 11 * 0.1;
count1=0;
count2=0;
label1.hidden = NO;
gameOver.hidden = YES;
score=0;
[super viewDidLoad];
;
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)regulator{
if(timer1)
{
[timer1 invalidate];
timer1 = nil;
}
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
}
timer4 =[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(conditioner) userInfo:nil repeats:YES];
;}
-(void)conditioner {
if (fabs(progress2.progress-progress1.progress)<=0.25 )
{
score=score+1;
scorenumber.text= [NSString stringWithFormat:#"%i",score];
[self newGame];
;
} else{
stop1=YES;
stop2=YES;
gameOver.hidden=NO;
stick.hidden=YES;
bg.hidden=YES;
progress1.hidden=YES;
progress2.hidden=YES;
supply.hidden=YES;
demand.hidden=YES;
}}
-(void)newGame{
progress1.progress=arc4random() % 11 * 0.1;}
- (IBAction)start:(UIButton *)sender {
progress2.progress=arc4random() % 11 * 0.1;
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(regulator) userInfo:nil repeats:YES];
[self regulator];
stop1=NO;
stop2=NO;
label1.hidden=YES;
UIButton *button1 = (UIButton *)sender;
button1.enabled = NO;
UIButton *button2 = (UIButton *)sender;
button2.enabled = NO;
}
- (IBAction)button1:(UIButton *)sender {
if(stop1==YES){button12.hidden = TRUE;}
progress2.progress=progress2.progress-0.05;
;
[self regulator];
count2=0;
count1 = count1 +1;
}
- (IBAction)button2:(UIButton *)sender {
[self regulator];
progress2.progress=progress2.progress+0.05;
if(stop2==YES){button22.hidden = TRUE;}
count1 =0;
count2 = count2+1;
}
#end
and my .h:
#import <UIKit/UIKit.h>
int count1;
int count2;
int score;
void *regulator;
void *newGame;
void *conditioner;
BOOL stop1;
BOOL stop2;
void *firstLaunch;
#interface ViewController : UIViewController{
IBOutlet UILabel *scorenumber;
IBOutlet UIImageView *stick;
IBOutlet UILabel *label1;
IBOutlet UIImageView *bg;
IBOutlet UILabel *supply;
IBOutlet UILabel *demand;
IBOutlet UILabel *gameOver;
IBOutlet UIProgressView *progress1;
IBOutlet UIProgressView *progress2;
IBOutlet UIButton *button12;
IBOutlet UIButton *button22;
NSTimer *timer1;
NSTimer *timer2;
NSTimer *timer3;
NSTimer *timer4;
}
- (IBAction)button1:(UIButton *)sender;
- (IBAction)button2:(UIButton *)sender;
#end
Thanks a lot for any help or information. I edited my question with the full code to give further explanation about the issue I'm facing. Regards.
This is actually a coding issue. MVC basics.
I believe you miss some understanding of things. So I'll explain:
IBAction - It's an action sent from the view to the controller.
IBOutlet - Meant for the controller to control the view.
On your code you are getting the sender (which should be read only when coding right) and you are trying to set it up. I assume you need to define a new IBOutlet to represent the button then connect it on your storyboard and then inside this function to make it enable/disabled.
Also a good practice would be to use "TRUE" and "FALSE" and not "YES/NO".
Hope this helps.
There are couple of ways you can approach this to make sure when user touches the button then it doesn't do anything.
It wasn't clear from your question so I assume on touch down of button you call (IBAction)button1. So Try
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so don't do anything
}
else
{
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}
If you want to hide it so that the user can't do anything try this
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so hide this button
//assuming you have connected an IBOutlet to your button1
button1.hidden = YES;
}
else
{
button1.hidden = NO;
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}

How to avoid keyboard hide & show when focus changes from UITextField and UIWebView?

I have a requirement in which the view contains one native UITextField and one UIWebView. The issue is if I switch the focus from UITextView to UIWebView, the keyboard window flicker(hides and then shows).
ie, I got UIKeyboardWillHideNotification and UIKeyboardDidShowNotification
But, this is not happening when I switch the other way. ies, I got only UIKeyboardDidShowNotification
Is there any way to avoid this flickering effect?
Note: I also notices if I have multiple UITextField and UIWebView, this issue is not happening with the same type of views.
I've solved this problem through the code below. Simply set webView.usesGUIFixes = YES; and it should solve your problem. The code below also lets you set a custom input view to use for the UIWebView keyboard:
UIWebView+GUIFixes.h
#import <UIKit/UIKit.h>
#interface UIWebView (GUIFixes)
/**
* #brief The custom input accessory view.
*/
#property (nonatomic, strong, readwrite) UIView* customInputAccessoryView;
/**
* #brief Wether the UIWebView will use the fixes provided by this category or not.
*/
#property (nonatomic, assign, readwrite) BOOL usesGUIFixes;
#end
UIWebView+GUIFixes.m
#import "UIWebView+GUIFixes.h"
#import <objc/runtime.h>
#implementation UIWebView (GUIFixes)
static const char* const kCustomInputAccessoryView = "kCustomInputAccessoryView";
static const char* const fixedClassName = "UIWebBrowserViewMinusAccessoryView";
static Class fixClass = Nil;
- (UIView *)browserView
{
UIScrollView *scrollView = self.scrollView;
UIView *browserView = nil;
for (UIView *subview in scrollView.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:#"UIWebBrowserView"]) {
browserView = subview;
break;
}
}
return browserView;
}
- (id)methodReturningCustomInputAccessoryView
{
UIView* view = [self performSelector:#selector(originalInputAccessoryView) withObject:nil];
if (view) {
UIView* parentWebView = self.superview;
while (parentWebView && ![parentWebView isKindOfClass:[UIWebView class]])
{
parentWebView = parentWebView.superview;
}
UIView* customInputAccessoryView = [(UIWebView*)parentWebView customInputAccessoryView];
if (customInputAccessoryView) {
view = customInputAccessoryView;
}
}
return view;
}
- (BOOL)delayedBecomeFirstResponder
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[super becomeFirstResponder];
});
return YES;
}
- (void)ensureFixedSubclassExistsOfBrowserViewClass:(Class)browserViewClass
{
if (!fixClass) {
Class newClass = objc_allocateClassPair(browserViewClass, fixedClassName, 0);
IMP oldImp = class_getMethodImplementation(browserViewClass, #selector(inputAccessoryView));
class_addMethod(newClass, #selector(originalInputAccessoryView), oldImp, "##:");
IMP newImp = [self methodForSelector:#selector(methodReturningCustomInputAccessoryView)];
class_addMethod(newClass, #selector(inputAccessoryView), newImp, "##:");
objc_registerClassPair(newClass);
IMP delayedFirstResponderImp = [self methodForSelector:#selector(delayedBecomeFirstResponder)];
Method becomeFirstResponderMethod = class_getInstanceMethod(browserViewClass, #selector(becomeFirstResponder));
method_setImplementation(becomeFirstResponderMethod, delayedFirstResponderImp);
fixClass = newClass;
}
}
- (BOOL)usesGUIFixes
{
UIView *browserView = [self browserView];
return [browserView class] == fixClass;
}
- (void)setUsesGUIFixes:(BOOL)value
{
UIView *browserView = [self browserView];
if (browserView == nil) {
return;
}
[self ensureFixedSubclassExistsOfBrowserViewClass:[browserView class]];
if (value) {
object_setClass(browserView, fixClass);
}
else {
Class normalClass = objc_getClass("UIWebBrowserView");
object_setClass(browserView, normalClass);
}
[browserView reloadInputViews];
}
- (UIView*)customInputAccessoryView
{
return objc_getAssociatedObject(self, kCustomInputAccessoryView);
}
- (void)setCustomInputAccessoryView:(UIView*)view
{
objc_setAssociatedObject(self,
kCustomInputAccessoryView,
view,
OBJC_ASSOCIATION_RETAIN);
}
#end

Resources