Prevent Calculator Syntax Error Crash? Xcode - iphone

Currently I am making a Calculator that allows the user to type out the formula they wish.
Ex. ((1+1)**9)+2)
This works just fine, I have used two methods for calculating this.
First:
answer = [[NSExpression expressionWithFormat:typeTo.text, nil] expressionValueWithObject:nil context:nil];
typeTo.text = [NSString stringWithFormat:#"%#", answer];
answerLabel.text = [NSString stringWithFormat:#"ANS { %# }", answer];
Second:
answer = [GCMathParser evaluate:typeTo.text];
Both of these calculate the problem without difficulty. But if the user types in:
(1+1)) [two brackets]
Both ways crash. This is one example of many different syntax errors. Is there a way to easily prevent this?
.
Additional info:
This is the way the second method catches the error:
#ifdef __COCOA_IMPLEMENTATION__
[NSException raise:#"Error in expression" format:#"error = %s", errStr];
#endif
THANKS :D

I haven't used either of those but based on the additional info, it may be throwing an NSException.
If that's the case, you can catch it and handle it. It looks like it might format a useful message telling you what's wrong with with expressions.
#try
{
// do work
}
#catch(NSException* ex)
{
// handle
}
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
Also, look to see if those libraries offer functions that pass in a ref to NSError. If so, you can use that.
There's also DDMathParser which is supposed to be a modern math parser and it looks like it takes NSError. Might be worth a look.
http://github.com/davedelong/DDMathParser

Related

How to create custom exception in objective c?

I am trying to achieve something like this in objective c.
#try{
//some code that will raise exception
}
#catch(CustomException e){//How to create this
//catching mechanism
}
#catch(NSException e){
//Generic catch
}
I need to create CustomException class and use it. Could you please help me in creating this CustomException and guide me in how to use this.
Thanks in advance.
Exceptions are very rarely used for control flow like this in Objective-C. I'm guessing you have a Java (or similar) background.
I'm not saying that you can't write code like this but it will feel very strange for other people looking at your code and could also possibly work badly if used by other peoples code if you don't completely isolate the exceptions so that it never reaches their code.
How it is commonly done in Objective-C
Exceptions are used for critical errors. If the error is expected (like it seems to be since you want to #try it) you should instead try and return an NSError. This is a design pattern that is used all over the Foundation and Cocoa frameworks and also third party frameworks. Look for example at networking, file reading/writing or JSON code (JSONObjectWithData:options:error:)
What you would do
What you do is add a error parameter (double pointer) at the end of your method that could fail, like this:
- (MyResultObject *)myMethodThatCouldFailWith:(MyObject *)myObject
error:(NSError **)error;
When someone (you or someone else) uses this method they can if they want to pass a NSError pointer that will get set if an error occurred, like this:
NSError *error = nil; // Assume no error
MyResultObject *result = [self myMethodThatCouldFailWith:myObject
error:&error];
if (!result) {
// An error occurred, you can check the error object for more information.
}
Note the ampersand (&) before the error parameter. This means that you are sending your error points as the argument so that inside the risky method that pointer can be changed to points to a new NSError object which can be read after the method returns.
Now, inside your method that could fail, you would set the error to a new NSError object if something went wrong (instead of raising an exception). It is also very common to return nil when an error occurs since that probably means that the calculation won't be able to complete or that the data is unreliable or irrelevant.
- (MyResultObject *)myMethodThatCouldFailWith:(MyObject *)myObject
error:(NSError **)error {
// Do something "risky" ...
MyResultObject *result = [MyResultObject somethingRiskyWith:myObject];
// Determine if things went wrong
if (!result) {
// Set error if a pointer for the error was given
if (error != NULL) {
*error = [NSError errorWithDomain:yourErrorDomain
code:yourErrorCode
userInfo:optionalDictionaryOfExtraInfo];
}
return nil;
}
// Everything went fine.
return result;
}
Now if the error returns you can identify what kind of error it was from the error code that you specified and you can read more detailed information in the user info dictionary (where you can add lots of information).
In the simplest case, I can declare a class using...
#interface CustomException : NSException
#end
#implementation CustomException
#end
...and the code is very much like what you posted:
#try{
#throw [[CustomException alloc] initWithName:#"Custom" reason:#"Testing" userInfo:nil];
}
#catch(CustomException *ce){
NSLog(#"Caught custom exception");
}
#catch(NSException *e){
NSLog(#"Caught generic exception");
}

Performing selector from within an Objective C block

I have been trying to use objective c blocks for the first time because I have really enjoyed using closures in languages such as Python and Haskell.
I have run into a problem however that I am hoping someone might be able to help with.
Below is a simplest version of the problem I am having.
typedef void(^BlockType)(NSString *string);
- (void)testWithtarget:(id)target action:(SEL)action
{
BlockType block = ^(NSString *string) {
[target performSelector:action withObject:data];
};
block(#"Test String"); // Succeeds
[self performSelector:#selector(doBlock:) withObject:block afterDelay:5.0f];
}
- (void)doBlock:(BlockType)block
{
block(#"Test String 2"); // Causes EXC_BAD_ACCESS crash
}
So it appears to be some sort of memory management issue which doesn't suprise me but I just don't have the knowledge to see the solution. Possibly what I am trying may not even be possible.
Interested to see what other people think :)
The block is not retained, since it is only present on the stack. You need to copy it if you want to use it outside the scope of the current stack (i.e. because you're using afterDelay:).
- (void)testWithtarget:(id)target action:(SEL)action
{
BlockType block = ^(NSString *string) {
[target performSelector:action withObject:data];
};
block(#"Test String"); // Succeeds
[self performSelector:#selector(doBlock:) withObject:[block copy] afterDelay:5.0f];
}
- (void)doBlock:(BlockType)block
{
block(#"Test String 2");
[block release];
}
It's a bit hap-hazard however since you're copying and releasing across method calls, but this is how you'd need to do it in this specific case.

iPhone, how can I evalute whether a text property is equal to a define'd string?

I have the following define'd constant set up.
#define EndDateNotSpecified "None"
But I can't seem to evaluate it, I've tried
if (btnEndDate.titleLabel.text != EndDateNotSpecified) {
and
if (btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified) {
I get compiler problems with each.
You missed an # for the string, remember to add this to every string constant:
#define EndDateNotSpecified #"None"
Close, just missing brackets around the method call, like
if ([btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified]) {
And in the future, it generally helps if you tell us what the specific compiler error was.
In objective C, you have to call a method in [] so the second one should be:
if ([btnEndDate.titleLabel.text isEqualToString:EndDateNotSpecified]) {
Don't use this because it will not always give correct result when you only compare the NSString pointer object
if (btnEndDate.titleLabel.text != EndDateNotSpecified) {
Generally, I think you should learn the basic Objective-C, your code doesn't look like a obj-c code. No [], no #"" for String:(

iPhone, objective c reassign and return pointer of method

Hey guys, lately I have been asking quite a few questions about memory management on the iPhone. Fortunately things are getting clearer. But I still struggle when it gets more complex: So is there something wrong with this in terms of memory mangement? My question and suggestions are in the comments...
//I get a text from a textfield
NSString *text = [[NSString alloc]initWithString:txtField.text];
NSMutableString *newText = [self replaceDynamicRegex:text];
[text release];
...
//The method replaces regex it finds in the text. The regex part is just pseudo code
//and I just interested in memory management
-(NSMutableString*)replaceDynamicRegex:(NSString*)txt{
NSString *currentTag = [NSString stringWithString:#"dynamiclyCreatedTag"];
//As long as we find a particuar regex (just pseuo code here) we replace it
while (currentTag != NULL) {
if([html stringByMatching:openingTag] == NULL){
break;
}
//regular expression
currentTag = [NSString stringWithString:[html stringByMatching:theRegex]];
//Get rid of the useless part of the currentTag pseudo code
NSString *uselessTagPart = #"uselessRegex";
//Reassignment of the pointer currentTag --> ok to do this? cause I did not alloc]init]?
//and instead used stringWithString wich then gets autoreleased
currentTag = [currentTag stringByReplacingOccurrencesOfRegex:uselessTagPart withString:#""];
//Reassignment of the pointer html --> Ok to do this? cause it is just a pointer and the
//object is being released after the method call (further up)
html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag];
}
//Do I need to autorelease this?
return html;
}
Your code looks correct memory-management-wise. Just remember, if you don't have call a method with alloc, new, retain, or copy in the method name, you don't have to worry about releasing.
One small point--your first 3 lines of code are redundant and inefficient. You shouldn't usually use initWithString--copy is usually a better choice when dealing with immutable objects, since behind the scenes a copy method can be replaced by a (less expensive) retain method. In your case, you don't even need to use copy--[self replaceDynamicRegex: txtField.text] will have the same result. Likewise, instead of [NSString stringWithString:[html stringByMatching:theRegex]], you can use simply use [html stringByMatching:theRegex] (since that method returns a new string).
Another note--html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] is incorrect. stringByReplacingOccurrencesOfRegex: returns an NSString, which can't be cast to an NSMutableString (you'll likely get a crash later on when you send a mutating method to the string). Instead, use [[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] mutableCopy]
Generally, when you see a method named xWithY, you can assume the string will be autorelease-d.
Therefore, you probably do not need to autorelease the value returned from -stringByReplacingOccurrencesOfRegex:withString:.
The rest of your code looks okay, to me.

Setter Getter oddness #property

I am having a really odd problem trying to set a simple float value to 1.
My property:
{
float direction;
}
#property(nonatomic)float direction;
Which is synthesized:
#synthesize direction;
I then used the following code:
- (void)setDirection:(float)_direction {
NSLog(#"Setter called with value of %f",_direction);
self->direction = _direction;
}
For testing purposes...
When I try to change the value with this,
[[w getCharacter] setDirection:1.0f];
where [w getCharacter] gives this:
return [[[self scene] gameLayer] player];
I get the warning, "setDirection not defined."
If I switch to dot notation([w getCharacter].direction), I get "confused by earlier errors, bailing out".
Here is where the weirdness starts. When I try to change the value, the debug message displays _direction = 0.00000. When I check the number later, its still 0.000. I am clearly trying to change it to 1, why is this not working?
The simplest explanation is that [w getCharacter] doesn't return the class of object you think it does. Only the class that has direction defined for it can respond to the message. You should test this by explicitly calling it with the class it defined for.
It is possible you did not include the header that defines the method.
Two probably unrelated issues:
The self->direction construction will work for a scalar value but it does an end run around the entire class concept. In this case just use: 'direction=_direction;` and it will set it directly.
Apple reserves all names that start with underscores for its own internal use. You should not use them because Objective-c has a global name space. It's possible that you can accidentally use an Apple variable that is defined deep within a framework. (This is why framework constants all start with NS,CF,CA etc.)
[Note: In the Comments, the author says to ignore this answer.
self.direction = 1; is syntactic sugar for
[self setDirection: 1];
when you call
-(void)setDirection:(float)_newDirection {
self.direction = _newDirection;
}
You seem to be telling the compiler or preprocessor to set up a recursive loop for you. The preprocessor (I think) changes it to this:
-(void)setDirection:(float)_newDirection {
[self setDirection: _newDirection];
}
If you call it simply
-(void)setDirection:(float)_newDirection {
direction = _newDirection;
}
the assignment should work (it worked for me just now)