The Alert View shows many time not one time - objective-c

I create UIAlertView in my function, the problem is it shows a lot of time when the function runs, how can I create an if statement to show only one time like if UIAlertView shows not show any more.
- (void)showAlert {
_myAlertView = nil;
_myAlertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Call_On_Hold",nil)
message:NSLocalizedString(#"Please_Wait",nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"Close_call",nil)
otherButtonTitles:nil, nil];
_myAlertView.tag = myAlertViewsTag;
[_myAlertView show];
}
Here is the function that my UIAlertView appear continuously instead of one time.
- (void) trafficTimerRun:(NSTimer*)theTimer
{
++ trafficTimerTicks;
pjmedia_rtcp_stat stat;
if (!get_stream_info([call_id intValue], &stat)) {
return;
}
LogDebug(TAG_SIP, #"Got %d bytes on stream 0 (previous: %d)", stat.rx.bytes, prev_bytes);
if (stat.rx.bytes == prev_bytes) {
if (trafficTimerTicks >= 10) {
// Steve-note: Here we need to show a pop-up message when the call in on hold when the trafficTimerTicks run.
[self showAlert];
LogError(TAG_SIP, #"No traffic received, hanging up");
// [theTimer invalidate];
// broken = YES; Steve note: The call shouldnt broke.
// [self hangup]; Steve note: The call shouldnt hangup.
}
}
}

Use a boolean:
bool alertIsShowing = false;
and in your updating method put something like this:
if (trafficTicks > 10){
if (!alertIsShowing){
alertIsShowing = true;
[self showAlert];
}
}
Then when your alert is dismissed, reset your boolean:
alertIsShowing = false;

Related

Enable button only after text fields are entered

Apple started rejecting my app (after yrs of approvals) - I have 2 text fields for a few char of last, first name, then press Go. They claim - I can't reproduce that the app crashes if you just press Go - when I run it it tries to send the request but kicks it back with an error 'No name - please reenter'. Whatever. To appease Apple I edited my text field entry method to now (see below) - but still not working. Please advise.
// Text Field methods
-(void)textFieldDidBeginEditing:(UITextField *)textField {
UIFont* boldFont = [UIFont fontWithName:#"Helvetica-Bold" size: 24];
if (textField == _lastName) {
[_lastName becomeFirstResponder];
[_lastName setFont:boldFont];
_lastName.autocorrectionType = UITextAutocorrectionTypeNo;;
_lastName.autocapitalizationType = UITextAutocapitalizationTypeNone;
_lastName.text = #"";
NSLog(#"user editing last...");
// Enable button once fields have values
if ([_lastName.text isEqual: #""] && [_firstName.text isEqual: #""])
{
_fwdButton.enabled = YES;
}
}
else {
[_firstName becomeFirstResponder];
[_firstName setFont:boldFont];
_firstName.autocorrectionType = UITextAutocorrectionTypeNo;;
_firstName.autocapitalizationType = UITextAutocapitalizationTypeNone;
_firstName.text = #"";
NSLog(#"user editing first");
// Enable button once fields have values
if ([_lastName.text isEqual: #""] && [_firstName.text isEqual: #""])
{
_fwdButton.enabled = YES;
}
}
}
I was able to add code similar to[https://stackoverflow.com/questions/2859821/disable-button-until-text-fields-have-been-entered][1]
to deal with the situation.

Boolean changes value before I can assign it

I have a curious problem where my boolean variable is changing before I can assign it to a variable to be read in my react native code for Spotify SDK.
I have pinpointed the EXACT location as to where it changes and I am currently trying to figure out why:
I have a boolean called isLoggedIn that is set equal to 1 if a successful login occurs. This variable then sets loggedIn to a boolean value which is sent to my React Native code:
else
{
// login successful
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
////THIS shows that isLoggedIn still equal to 1.
[self initializePlayerIfNeeded:[RNSpotifyCompletion onComplete:^(id unused, RNSpotifyError* unusedError) {
NSLog(#"What is the value of isLoggedIn right after %#", [self isLoggedIn]);
/////NOW the isLoggedIn variable is now equal to 0.
// do UI logic on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[authController.presentingViewController dismissViewControllerAnimated:YES completion:^{
_loggingIn = NO;
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
NSNumber* loggedIn = [self isLoggedIn]; /////this is the line we need to be == 1
resolve(loggedIn);
if(loggedIn.boolValue)
{
[self sendEvent:#"login" args:#[]];
}
}];
});
}]];
}
So obviously I assume that it is due to this line right?:
[self initializePlayerIfNeeded:[RNSpotifyCompletion onComplete:^(id unused, RNSpotifyError* unusedError)
Which is running this method: initializePlayerIfNeeded but when I read the value of the isLoggedIn variable at the end of this method it still shows a boolean value of 1 (look at last line):
-(void)initializePlayerIfNeeded:(RNSpotifyCompletion*)completion
{
if(![self hasPlayerScope])
{
[completion resolve:nil];
return;
}
// ensure only one thread is invoking the initialization at a time
BOOL initializedPlayer = NO;
NSError* error = nil;
BOOL allowCaching = (_cacheSize.unsignedIntegerValue > 0);
#synchronized(_player)
{
// check if player is already initialized
if(_player.initialized)
{
initializedPlayer = YES;
}
else
{
initializedPlayer = [_player startWithClientId:_auth.clientID audioController:nil allowCaching:allowCaching error:&error];
}
}
// handle initialization failure
if(!initializedPlayer)
{
[completion reject:[RNSpotifyError errorWithNSError:error]];
return;
}
// setup player
_player.delegate = self;
_player.playbackDelegate = self;
if(allowCaching)
{
_player.diskCache = [[SPTDiskCache alloc] initWithCapacity:_cacheSize.unsignedIntegerValue];
}
// attempt to log in the player
[self loginPlayer:completion];
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
////THIS shows that isLoggedIn still equal to 1.
}
So that method finishes up with the value still equal to 1, but why after that method returns does the next line show that isLoggedIn equal to 0? I am extremely new to objC so every bit of knowledge is helpful for me. I am using this React Native Spotify library from github: https://github.com/lufinkey/react-native-spotify
You can find the exact file I'm working with here: https://github.com/lufinkey/react-native-spotify/blob/master/ios/RNSpotify.m
What else would you need to help solve this?
EDIT: here's the method that changes the isLoggedIn:
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isLoggedIn)
{
if(!_initialized)
{
return #NO;
}
else if(_auth.session == nil)
{
return #NO;
}
return #YES;
}

What is a convenient way to check UITextFields for errors before allowing a form to submit?

I've been at this all day and just can't get my head around it. On a form in my app, I'm using -[UITextFieldDelegate textFieldDidEndEditing]: to register any errors and store them in an NSMutableArray instance variable formErrors.
I intend to use the formErrors when my submit button is pressed, or perhaps to disable the button disabled while there are errors on the form. The problem is the error count goes all over the place. I've just ended up confusing myself as you can see my code where I'm incrementing and decrementing in order to try and control what's going on but just confusing myself more.
Error messages get put on formErrors like this:
-(void)textFieldDidEndEditing:(UITextField *)textField {
if ( textField == [self nameField] ) {
if ( ([[textField text] isEqualToString:#""]) ) {
[formErrors addObject:#"What is your name?"];
errorCount++;
} else {
errorCount--;
if ( ([[textField text] length] < 2) || ([[textField text] length] > 20) ) {
[formErrors addObject:#"Name must contain a minimum of 2 and a maximum of 20 characters only."];
errorCount++;
} else {
errorCount--;
if ([[textField text] rangeOfCharacterFromSet:alphaSet].location != NSNotFound) {
[formErrors addObject:#"Name must contain letters and spaces only."];
errorCount++;
}
}
}
}
if (textField == [self ageField]) {
if ( ([[textField text] isEqualToString:#""]) ) {
[formErrors addObject:#"How old are you?"];
errorCount++;
} else {
errorCount--;
if ( ([[textField text] intValue]) < 1 || ([[textField text] intValue] > 120) ) {
[formErrors addObject:#"Please enter an age using a number between 1 and 120."];
errorCount++;
} else {
errorCount--;
if ([[textField text] rangeOfCharacterFromSet:numericSet].location != NSNotFound) {
[formErrors addObject:#"Age must be given in numbers."];
errorCount++;
}
}
}
}
My instance var:
{
NSMutableArray *formErrors;
}
Then initialise it in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
formErrors = [[NSMutableArray alloc] init];
Then in prepareForSegue: I have some temporary code to check things are working:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
int errCount = [formErrors count];
// check if all textfield values are filled in if not then disallow form submit
for (NSString *error in formErrors) {
NSLog(#"Total %d errors, \n Error Message: %#", errCount, error);
}
All I want to do is, as I enter and leave fields, check if there are any errors; if there are, just store the error message in formErrors, so I can do what I need to do in the prepareForSegue:. Is this even the right approach? I've tried doing this many different ways but just keep on going in circles.
The submit button is linked to my segue and also is an outlet so I can enabled and disable it as I please.
Help would be appreciated
Kind regards
Your approach is a bit redundant. Validate your fields upon submission, cancel submission if there are any errors:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
NSMutableArray *errors = [NSMutableArray array];
if (self.nameTextField.text.length > 21) {
[errors addObject:#"Name cannot be longer than 21 symbols"];
}
else if (!self.nameTextField.text.length) {
[errors addObject:#"Please enter your name"];
}
if (!self.passwordTextField.text.length) {
[errors addObject:#"Please enter password"];
}
else if (!self.confirmPasswordTextField.text.length) {
[errors addObject:#"Please confirm your password"];
}
else if (self.passwordTextField.text.length < 6) {
[errors addObject:#"Password is too short, use at least 6 characters."];
}
else if (![self.passwordTextField.text isEqualToString:self.confirmPasswordTextField.text]) {
[errors addObject:#"Passwords do not match"];
}
if (!self.emailTextField.text.length) {
[errors addObject:#"Please enter your e-mail"];
}
if (!self.image) {
[errors addObject:#"Please choose a photo"];
}
if (errors.count) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:[errors componentsJoinedByString:#"\n"]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil] show];
return NO;
}
return YES;
}
You're on the right path, but here are a couple of observations.
First I would get rid of all the errorCount++ and errorCount-- lines. They don't make sense, because you can always count the items in your error array.
Every time you check your input fields, clear your error array, otherwise you will be having errors that might have been already corrected.
Inside your -(void)textFieldDidEndEditing:(UITextField *)textField method, don't only check the textfield that has been edited, because you wold need to keep track of the errors that were before, the ones that were corrected, and the new ones... too much trouble.
I think it's best to create a new method that checks all the information and returns an array of errors. Call this routine from textFieldDidEndEditing.
- (NSArray *)checkInputs
{
NSMutableArray *errors = [NSMutableArray array];
// Loop through the textfields and fill your array
return (NSArray *)errors;
}

Cocoa touch how to run a UIAlertView inside a while loop

I have an int where someone sets how many spellings there are called samount and a int called amountdone and they are both set to 0 like this NSInteger samount = 0;
NSInteger amountdone = 0;at the start. I have a button and when it is clicked it calls the method Startese. The code is
- (IBAction)Startest:(id)sender {
UIAlertView *amount = [[UIAlertView alloc] initWithTitle:#"Amount" message:#"How much spellings are there" delegate:self cancelButtonTitle:#"That amount" otherButtonTitles:nil];
[amount setAlertViewStyle:UIAlertViewStylePlainTextInput];
[[amount textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeNumberPad];
[amount setTag: 0];
[amount show];
}
And I need a UIAlertView to display its self and then add its text in to an array I have got the alertView clickedButtonAtIndex void working like this
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (alertView.tag)
{
case 0: /* amount alert */
{
samount = [[alertView textFieldAtIndex:0]text];
UIAlertView *spellings = [[UIAlertView alloc]initWithTitle:#"Enter Spelling " message:#"Pleaseenter ONE of the spellings" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[spellings setTag:1];
[spellings setAlertViewStyle:UIAlertViewStylePlainTextInput];
[spellings show];
}
break;
case 1: /* Spellings alert*/{
while (amountdone < samount) {
amountdone = amountdone + 1;
self.myarry = [[alertView textFieldAtIndex:0]text];
}
}
break;
}
}
`
It works the first time but once the while loop activates it freezes the app does anyone know how to fix this
Create method to create and launch your alertView and in clickedButtonAtIndex: method call after delay;
[self performSelector:#selector(yourMethodForLaunchingAlertView:)
withObject:objectOrNill
afterDelay:0.5];
Hope this help.
Well, the reason it is locking up is because amountdone is never set to anything other than the initialization of 0, so amountdone < samount is likely always true, and therefore your while loop continues forever.
When is amountdone suppose to be set?
Edit
I don't think you want a while loop. Based on what you've got
while (amountdone < samount) {
amountdone = amountdone + 1;
self.myarry = [[alertView textFieldAtIndex:0]text];
}
The while loop provides no value, it may as well be an if condition because you're setting the same thing over and over again (which setting NSString to NSArray doesn't make sense either).
I think it's time to take a step back and reevaluate the problem you're solving and your approach. Maybe I can help if you describe the use-case/business requirement.

Creating defaults in Objective C

I'm working on my first big application and have inadvertently driven myself into a panic from a small flaw in design. I've made a timer that counts at the touch of a button, and upon a second touch, transitions into a secondary timer with a 60 second countdown.
The problem lies in the fact that once I repeat this process, the (kRest-Pause) call is remembered. I'm looking to create a default countdown of 60 without the continuation of the time. Should I kill it in memory and create a new instance for each subsequent button press? Or is there a logic game that looks at the aggregate time and corrects with each new occurance?
I don't know how to approach this, I'm done attempting -if statements with returns as I have learned that's not how that works. Any help would be appreciated
EDIT: Sorry for the lack of clarity. I'm pretty green on programming of any caliber. So far, the main timer counts down from 10-0 then up from 0-120. In that 2 minute period, if the button is pressed again, the 0-120 count is paused for 60 seconds or until the button is pressed for the third time. If this 60-0 countdown reaches 0 or is interrupted, the initial 0-120 countup resumes its count. My issue is that if I push the button a fourth time, the 60-0 countdown is resumed from the moment of interruption without retaining a default of 60. This is why I named the post "creating defaults in Objective C". It's the wrong use of the word and way to broad, but it's what I could come up with.
kRest=60
-(void)increase{
if (mode==1){
count++;
int d = 10-count;
if (d==0){ timeLabel.text = #"Begin";
[self startPlaybackForPlayer: self.startTimerSound];}
else {timeLabel.text = [NSString stringWithFormat:#"%d", abs(d)];}
if(d<0){
//workign out
active = TRUE;
if (d <= -20) {
[self stopTimer];
}
}
else{
//no user interface
active = FALSE;
}
}
else{
pause++;
countdownLabel.text = [NSString stringWithFormat:#"%d!", (kRest-pause)];
NSLog(#"Paused at time %d", pause);
UIColor *textColor = nil;
if (pause % 2==0){
textColor = [UIColor yellowColor];
}
else{
textColor = [UIColor redColor];
}
timeLabel.textColor = textColor;
if ((kRest-pause)==0){
countdownLabel.text = [NSString stringWithFormat:#"%d!",pause];
mode=1;
pause=0;
[button setTitle:#"Stop" forState:UIControlStateNormal];
repCount++;
myRepCount.text = [NSString stringWithFormat:#"Rep Count: %d", repCount];
countdownLabel.text = #"";
}
}
}
if you are using a timer to access this counter then you should be able to update the counter that the timer uses. Just make sure you synchronize the object so you dont edit while you are reading.
here is an example of what I mean.
int counter = 0;
int limit = 60;
- (BOOL) incrementUntilReached{
#synchronized(self){
if (counter == limit) return YES;
counter++;
return NO;
}
}
- (void) resetTimer{
#synchronized(self){
counter = 0;
}
}
- (int) countsLeft {
#synchronized(self){
return limit - counter;
}
}