Regular expression syntax in Objective-C - objective-c

I have looked everywhere and can't find a solution that works for this.
I have:
- (BOOL) textFieldShouldEndEditing:(UITextField *)textField {
NSString *regEx = #"/^[1-9]\d*(\.\d+)?$/";
NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch];
if (r.location == NSNotFound) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Entry Error"
message:#"Enter only numbers or decimals"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
return NO;
} else {
return YES;
}
}
But the regular expression isn't working. I want it to only accept numbers and decimals. I know that there is some weird difference in code with regex where you have to double up on backslashes or something, but I couldn't figure it out.

Remove the [1-9] at the beginning as well as the forward slashes and escape the backslashes so it is just:
"^\\d*(\\.\\d+)?$"
See How can I escape this regex properly in Objective-C?

Related

Error message on Xcode that I don't understand

I am getting an error message on my Xcode - Objective C.
Arithmetic on pointer to interface "UILabel", which is not constant size for this architecture and platform.
if([self checkforwin]){
NSString*winner = nil;
if (playertoken==1)
winner =#"Player 2 Wins";
_result1 = _result1+1
else if (playertoken==2)
_result2 = _result2 +1
winner =#"Player 1 Wins";
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Result"
message: winner
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[self resetboard];
[_audioPlayer play];
[alert show];
Any Ideas how to get rid of them??
The error shows on both the result1 and result2. Trying to add a score to my game.
Use parenthesis while using condition. Also don't set string to nil, set it with empty string #""
if([self checkforwin]){
NSString *winner = #"";
if (playertoken==1) {
winner =#"Player 2 Wins";
_result1 = _result1 + 1;
}
else if (playertoken==2) {
winner =#"Player 1 Wins";
_result2 = _result2 + 1;
}
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Result"
message: winner
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[self resetboard];
[_audioPlayer play];
[alert show];
}
You are trying to add 1 to the UILabel. You need an integer variable to do the increment. Either declare the _result 1 and 2 as int type variable or declare a int variable and increment it, and pass it to UILabel .text property
_result1 = _result1+1
here _result1 must be a integer variable.
You need to something like:
Declare the result1 as int,
#property(assign) int result1;
and this line should be fine
_result1=_result1+1;

Randomizing Alert view text for Objective C

I am new to programming. I am having trouble finding out what all is wrong with this. It is an alert view that i am trying to randomize the text displayed in the message.
-(void)alert:(id)sender{
int randomNumber;
randomNumber = (randomNumber() %3 + 1);
NSLog(#"%i", randomNumber);
if (randomNumber == 1) {
self.YouWin.text = [NSString stringWithFormat:#"You Win"];
}
else if (randomNumber == 2) {
self.YouWin.text = [NSString stringWithFormat:#"You Lose"];
}
else if (randomNumber == 3) {
self.YouWin.text = [NSString stringWithFormat:#"Tie"];
}
NSLog(#"%#",YouWin);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Hello" message:[NSString stringWithFormat:#"%#",YouWin] delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
button.hidden = YES;
Try this one:
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Hello"
message:self.YouWin.text
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
You needed text-value stored in YouWin, but you passed the YouWin object itself.
*Note: you can use arc4random() for generating random numbers.
There are many good suggestions; I agree with AKB8085.
Replacing the randomNumber() with arc4random() will help at compile time.
But you might want to re-think implementing a random number generator. The reason is in fairness to your user. I pose the question, “Is it fair to assume you want your user to guess a number with this large of a number range?”
Did you Know?
Using the arc4random(3), rand(3), or random(3) you are using a C function.
You are asking the user to guess a number with the following ranges:
arc4random(3) = 0 to 4294967296
rand(3) and random(3) that top out at a RAND_MAX of 0x7fffffff (214748647)
To help in answering your question, answer the following requirement questions:
Is there a min/max range restraint?
What type of compelling delays will happen
by using arc4random(3), rand(3), or random(3)?
Is using NSArray like in the Fisher–Yates_shuffle a better answer?
SUGGESTION:
Read an article on random numbers and NSArray.
NOTE:
Random numbers tend to task the compiler and your user experience will be hindered.
As Anoop noted you are using stringWithFormat but you're not providing a format string at all.
You should do
[NSString stringWithFormat:#"%#", #"You Win"];
but that's extremely redundant, although correct, and it's totally equivalent to just using #"You Win".
Also an advice for the general approach on the problem. Instead of having a big if-else statement, it's better to store all your string into a data structure and then randomly access to it.
In code this would translate to
NSArray * outcomes = #[ #"You Win", #"You lose", #"Tie" ];
int randomIndex = arc4random_uniform(outcomes.count);
NSString * randomOutcome = outcomes[randomIndex];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Hello"
message:randomOutcome
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
button.hidden = YES;
Note the usage of arc4random_uniform() that gives you back a random number between 0 and the argument provided, excluded.
Replace
randomNumber = (randomNumber() %3 + 1);
with
randomNumber = arc4random() %3 + 1;
Also use this...
if (randomNumber == 1) {
self.YouWin.text = [NSString stringWithFormat:#"You Win"];
}
else if (randomNumber == 2) {
self.YouWin.text = [NSString stringWithFormat:#"You Lose"];
}
else if (randomNumber == 3) {
self.YouWin.text = [NSString stringWithFormat:#"Tie"];
}
NSLog(#"%#",YouWin);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Hello"
message:self.YouWin.text
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
button.hidden = YES;

For line Objective-C

I'm making an iOS code interpreter. I have all the checking done but as of now you can only enter one command. I want the user to be able to enter multiple commands into a UITextView. What I plan do with the text view is pass each line the my IF statement line.
Does anyone know of a way to say, pass each line one by one into a if statement line?
- (IBAction)runCommad:(id)sender {
//Alert
NSString *alertCheck = #"alert(";
NSRange alertCheckRange = [code.text rangeOfString : alertCheck];
//Logger
NSString *logCheck = #"log(";
NSRange logCheckRange = [code.text rangeOfString : logCheck];
if (alertCheckRange.location != NSNotFound) {
//If the compiler sees alert()...
NSString *commandEdit;
commandEdit = code.text;
commandEdit = [commandEdit stringByReplacingOccurrencesOfString:#"alert(" withString:#""];
commandEdit = [commandEdit stringByReplacingOccurrencesOfString:#")" withString:#""];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Syn0" message:commandEdit delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}else if (logCheckRange.location != NSNotFound) {
//If the compiler sees log()...
NSString *commandEdit;
commandEdit = code.text;
commandEdit = [commandEdit stringByReplacingOccurrencesOfString:#"log(" withString:#""];
commandEdit = [commandEdit stringByReplacingOccurrencesOfString:#")" withString:#""];
logFile = [NSString stringWithFormat:#"%#\n%#", logFile,commandEdit];
logTextView.text = logFile;
}
}
First, get your string components to evaluate:
NSString *text = [textView text];
NSArray *components = [text componentsSeperatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
You can't use a switch with a string, so you'll need to check for each case with an if:
for (NSString *string in components)
{
if ([string isEqualToString:#"The first string you're matching"])
{
//Do something because you found first string
}
if([string isEqualToString:#"The second string you're matching"])
{
//Do something else
}
}
That's the idea.
Two suggestions, first if you are comfortable with blocks you can use NSString's:
(void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block
This method will call the block passing it each line in the original string in order. If you want to stop before processing each line you set stop to YES.
Alternatively you can use NSString's:
(NSArray *)componentsSeparatedByString:(NSString *)separator
This will break a string up into components based on separator. Use this in a for enumeration:
for(NSString *nextLine in [originalString componentsSeparatedByString:#"\n"])
{
// process nextLine, break from loop to stop before processing each line
}

IF clause is not validating NSString function return?

I have the function below that validates the return of another function (function searchPlaces that returns NSString). When I run it, it seems that the if clause is not being called, because the NSLog(#"Function Return: %#",nova url); appears in Console.
Can someone tell me if there's any mistake in the code? (For sure there is a mistake!)
- (void) buttonPushRandomViewController1 {
UIViewController *randomViewController = [self randomViewController3];
NSString *novaurl = [self searchPlaces];
NSLog(#"Function Return: %#",novaurl);
if (novaurl == #"OK") {
randomViewController.title = #"Resultado";
[self.master pushViewController:randomViewController animated:YES];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:novaurl]];
[webView loadRequest:request];
}else if (novaurl == #"ZERO_RESULTS") {
UIAlertView *zeroResults = [[UIAlertView alloc] initWithTitle: #"Ops!" message: #"Sorry, nothing found!"
delegate: self cancelButtonTitle: #"OK" otherButtonTitles: nil];
[zeroResults show];
[zeroResults release];
}
}
Thanks in advance!
You should not comparing NSStrings with the == operator. The == operator performs reference equality on Objective-C object types: it only returns true if both operands refer to the exact same object. Even if two strings are copies of each other, == will return false if they refer to different instances.
You want to use value equality instead. You can compare strings using the -isEqualToString: method:
if ([novaurl isEqualToString:#"OK"]) {
...
}
You should use isEqualToString: method of NSString to check for equality of strings. == operator does a pointer comparison and sometimes it will return NO although the contents of the strings are the same.

Objective-C passing around ... nil terminated argument lists

Having some issues with the ... in ObjectiveC.
I'm basically wrapping a method and want to accept a nil terminated list and directly pass that same list to the method I am wrapping.
Here's what I have but it causes an EXC_BAD_ACCESS crash. Inspecting the local vars, it appears when otherButtonTitles is simply a NSString when it is passed in with otherButtonTitles:#"Foo", nil]
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles] autorelease];
[alert show];
}
How do I simply siphon from the argument incoming to the argument outgoing, preserving the exact same nil terminated list?
You can't do this, at least not in the way you're wanting to do it. What you want to do (pass on the variable arguments) requires having an initializer on UIAlertView that accepts a va_list. There isn't one. However, you can use the addButtonWithTitle: method:
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil] autorelease];
if (otherButtonTitles != nil) {
[alert addButtonWithTitle:otherButtonTitles];
va_list args;
va_start(args, otherButtonTitles);
NSString * title = nil;
while(title = va_arg(args,NSString*)) {
[alert addButtonWithTitle:title];
}
va_end(args);
}
[alert show];
}
This is, of course, very problem-specific. The real answer is "you can't implicitly pass on a variable argument list to a method/function that does not have a va_list parameter". You must therefore find a way around the problem. In the example you gave, you wanted to make an alertView with the titles you passed in. Fortunately for you, the UIAlertView class has a method that you can iteratively call to add buttons, and thereby achieve the same overall effect. If it did not have this method, you'd be out of luck.
The other really messy option would be to make it a variadic macro. A variadic macro looks like this:
#define SHOW_ALERT(title,msg,del,cancel,other,...) { \
UIAlertView *_alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:del cancelButtonTitle:cancel otherButtonTitles:other, ##__VA_ARGS__] autorelease]; \
[_alert show]; \
}
However, even with the variadic macro approach, you'd still need a custom macro for each time you wanted to do this. It's not a very solid alternative.
How about constructing an NSInvocation object? Since arguments must be passed by pointer, you could pass the pointer to the nil-terminated list.
You could also iterate over the parameters using marg_list() and construct a nil-terminated list yourself.
These are just simple suggestions; I haven't tried them out.
This is specific to the OP's UIAlertView-wrapping case, and tested only on iOS7: It appears that once a UIAlertView has been initialised with otherButtons:nil, and then has its style set to UIAlertViewStylePlainTextInput it doesn't call its delegate's alertViewShouldEnableFirstOtherButton: to validate input. I'm not sure if this is a bug or intended behaviour but it broke my principle of least astonishment. This is reproducible with the following (I'll assume the delegate's alertViewShouldEnableFirstOtherButton: is implemented):
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Title"
message:#"message"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[av setAlertViewStyle:UIAlertViewStylePlainTextInput];
[av addButtonWithTitle:#"OK"];
[av show];
The solution, since UIAlertView happily accepts otherButtons:nil, is to initialise UIAlertView with otherButtonTitles (which can be nil), and iterate over the variadic arguments, as above:
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles] autorelease];
// add your [alert setAlertViewStyle:UIAlertViewStylePlainTextInput] etc. as required here
if (otherButtonTitles != nil) {
va_list args;
va_start(args, otherButtonTitles);
NSString * title = nil;
while(title = va_arg(args,NSString*)) {
[alert addButtonWithTitle:title];
}
va_end(args);
}
[alert show];
}