Using Error Handling in DDMathParser - swift2

I am using DDMathParser library in my project and I want to use error handling. I want the error to be displayed to user if he inputs wrong expression. What would be my catch block to detect and display related error and its position. Following is my sample code:
do{
var X = "(3 + 4" //Missed Closed Parenthesis
let evaluator = Evaluator()
let expression = try Expression(string: X)
let value = try evaluator.evaluate(expression)
}
catch
{
}
According to DDMathParser it should be Grouping error and by using Range with it it should specify its location where parenthesis got missed or any other error type occurred. Here is its Documentation

You have to cast the error as a GroupedTokenError to access the specific DDMathParser error messages.
do {
let X = "(3 + 4"
let evaluator = Evaluator()
let expression = try Expression(string: X)
let value = try evaluator.evaluate(expression)
} catch let error as GroupedTokenError {
print(error._code) // 1
print(error.kind) // MissingCloseParenthesis
print(error.range) // 6..<6
} catch let error as NSError {
print(error.debugDescription)
}
Note that you also have to add a generic error catching block for non-DDMathParser errors (in my example a generic ErrorType will be bridged to an NSError to display the contents the Cocoa way).

Related

What does Some() do on the left hand side of a variable assignment?

I was reading some Rust code and I came across this line
if let Some(path) = env::args().nth(1) {
Inside of this function
fn main() {
if let Some(path) = env::args().nth(1) {
// Try reading the file provided by the path.
let mut file = File::open(path).expect("Failed reading file.");
let mut content = String::new();
file.read_to_string(&mut content);
perform_conversion(content.as_str()).expect("Conversion failed.");
} else {
println!(
"provide a path to a .cue file to be converted into a MusicBrainz compatible tracklist."
)
}
}
The line seems to be assigning the env argument to the variable path but I can't work out what the Some() around it is doing.
I took a look at the documentation for Option and I understand how it works when used on the right hand side of = but on the left hand side I am a little confused.
Am I right in thinking this line is equivalent to
if let path = Some(env::args().nth(1)) {
From the reference :
An if let expression is semantically similar to an if expression but
in place of a condition expression it expects the keyword let followed
by a refutable pattern, an = and an expression. If the value of the
expression on the right hand side of the = matches the pattern, the
corresponding block will execute, otherwise flow proceeds to the
following else block if it exists. Like if expressions, if let
expressions have a value determined by the block that is evaluated.
In here the important part is refutability. What it means refutable pattern in here it can be in different forms. For example :
enum Test {
First(String, i32, usize),
Second(i32, usize),
Third(i32),
}
You can check the x's value for a value for 3 different pattern like :
fn main() {
let x = Test::Second(14, 55);
if let Test::First(a, b, c) = x {}
if let Test::Second(a, b) = x {} //This block will be executed
if let Test::Third(a) = x {}
}
This is called refutability. But consider your code like this:
enum Test {
Second(i32, usize),
}
fn main() {
let x = Test::Second(14, 55);
if let Test::Second(a, b) = x {}
}
This code will not compile because x's pattern is obvious, it has single pattern.
You can get more information from the reference of refutability.
Also you are not right thinking for this:
if let path = Some(env::args().nth(1)) {
Compiler will throw error like irrefutable if-let pattern because as the reference says: "keyword let followed by a refutable pattern". In here there is no refutable pattern after "let". Actually this code tries to create a variable named path which is an Option and this make no sense because there is no "If" needed,
Instead Rust expects from you to write like this:
let path = Some(env::args().nth(1)); // This will be seem like Some(Some(value))
The other answers go into a lot of detail, which might be more than you need to know.
Essentially, this:
if let Some(path) = env::args().nth(1) {
// Do something with path
} else {
// otherwise do something else
}
is identical to this:
match env::args().nth(1) {
Some(path) => { /* Do something with path */ }
_ => { /* otherwise do something else */ }
}

unable to use optional int "possibleNumber" in optional binding

I'm new to Swift and is trying to learn the concept of optional binding. I have came up with the following code:
let possibleNumber = Int("123")
possibleNumber.dynamicType
if let actualNumber = Int(possibleNumber){
print("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
print("\(possibleNumber) could not be converted to an int")
}
Xcode playground output error message:
value of optional type "int?" not unwrapped, did you mean to use "!" or "?"
However, when I added the "!" to if let actualNumber = Int(possibleNumber!){
let possibleNumber = Int("123")
possibleNumber.dynamicType
if let actualNumber = Int(possibleNumber!){
print("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
print("\(possibleNumber) could not be converted to an int")
}
Xcode display another error message:
initialiser for conditional binding must have Optional type, not int
Why is this happening?
The result of
let possibleNumber = Int("123")
is an optional Int - Int?
Then you're trying to create another Int with
Int(possibleNumber)
which does not work because the initializer expects a non-optional type.
The error message is related to the initializer rather than to the optional binding.
Try this to get the same error message.
let possibleNumber = Int("123")
let x = Int(possibleNumber)
In your second example when you initialize an Int with an implicit unwrapped Int! argument you get a non-optional Int and the compiler complains about the missing optional.
In the if let construct
if let actualNumber = Int(possibleNumber!){
print("\(possibleNumber) has an integer value of \(actualNumber)")
}
you don't need to use the Int initializer. You simply need to write
if let actualNumber = possibleNumber {
print("\(possibleNumber) has an integer value of \(actualNumber)")
}
Now Swift will try to unwrap possibleNumber. If the operation does succeed the unwrapped value is put inside actualNumber and the THEN block executed.

Swift 2.0 - is the programming logic different from languages?

I am new to Swift 2.0 programming. I made an app integrate with Parse. Following is the snippet of my code
private func isIdNotFound() ->Bool{
var notFound = true
let query = PFQuery(className: "Customer")
query.whereKey("customerId", equalTo: self.id)
query.findObjectsInBackgroundWithBlock{
(objects : [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil{
print(objects)
notFound = false
print(notFound)
}
}
print(notFound)
return notFound
}
The console:
true
<Customer: 0x7feccbf07ef0, objectId: AiPH5pNgum, localId: (null)> {
customerId = wilson93;
email = 123;
password = 123;
}])
false
Why is it that it prints true then only it runs the logic and print false. As far as other languages such Java, it should print false twice.
As mentioned in comments, your code is query.findObjectsInBackgroundWithBlock:. Here, Background is the keyword. Because you are searching asynchronously, therefore not necessarily in the order the code is written, the second instance of print(notFound) is executed before the instance in the block.
You can tell because, if read out loud, the two print statements are right next to each other (excluding braces) but notFound is not printed twice in succession. objects is printed after the first (second instance in code) print statement but before the other one.
var notFound = true
query.findObjectsInBackgroundWithBlock{
(objects : [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil{
print(objects) //this comes second
notFound = false
print(notFound) //then this comes last
}
}
print(notFound) //this runs first
See the documentation for PFQuery here. It says, in italics, that the search is performed asynchronously.
From the doc:
Finds objects asynchronously and calls the given block with the results.
- (void)findObjectsInBackgroundWithBlock:(nullable PFQueryArrayResultBlock)block
Parameters
IIRC, this means that the search is run on another thread.
#Community correct me if I'm wrong.

Logging in Swift 2.0

I am new to XCode and work on Android Studio previously. In Android Studio, there is log cat to log different types of messages for debugging purposes.
Is this available in XCode?
All I found is NSLog which prints the date and the statement without coloring like in log cat. Is there an easier way ?
You can use the print method.
Check out these handy Apple docs.
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
using XCodeColors Library https://github.com/robbiehanson/XcodeColors you can log different types of messages each in a unique color so that you can find error logs faster
also i customized the code like this to get coloring, which class, function, and line number did the call
struct RZLog
{
static let ESCAPE = "\u{001b}["
static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color
static let RESET_BG = ESCAPE + "bg;" // Clear any background color
static let RESET = ESCAPE + ";" // Clear any foreground or background color
static let A = "fg255,0,0;"
static let B = "fg0,0,255;"
static let C = "fg16,128,0;"
static func Error<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(A)**ERROR \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
static func Debug<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(B)**DEBUG \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
static func VIP<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(C)**VIP \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
}
If you want to use different CocoaLumberjack:
https://github.com/CocoaLumberjack/CocoaLumberjack
Which provides some more advantages over simple logging. And it can also be used with colors:
http://code.tutsplus.com/tutorials/cocoalumberjack-logging-on-steroids--mobile-15287
You can use Printer a new logging experience in Swift 3.x.
It has many functions to add logs in various ways.
Usage:
To log a success message:
Printer.log.success(details: "This is a Success message.")
Output:
Printer ➞ [✅ Success] [⌚04-27-2017 10:53:28] ➞ ✹✹This is a Success message.✹✹
[Trace] ➞ ViewController.swift ➞ viewDidLoad() #58
Disclaimer: This library has been created by me.

Swift distance() method throws fatal error: can not increment endIndex

I was trying to find a substring match in a string, and get the matched position.
I can't figure out what's wrong with the following code:
let str1 = "hello#゚Д゚"
let cmp = "゚Д゚"
let searchRange = Range(start: str1.startIndex, end: str1.endIndex)
let range = str1.rangeOfString(cmp, options: .allZeros, range: searchRange)
println("\(searchRange), \(range!)") // output: 0..<9, 6..<9
let dis = distance(searchRange.startIndex, range!.startIndex) // fatal error: can not increment endIndex! reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
// let dis = distance(searchRange.startIndex, range!.endIndex) // This will go and output: distance=7
println("distance=\(dis)")
As the comments suggested, although the range had valid values, the distance() method threw a fatal error.
If I'm wrong about the use of distance(), what method should I use to archive the target?
Any advice would be helpful. Thanks.
range!.startIndex points here:
"hello#゚Д゚"
^
But, in this case, #゚ is a single character in Swift.
Therefore, This code:
for var idx = searchRange.startIndex; idx != range!.startIndex; idx = idx.successor() {
println("\(idx): \(str1[idx])");
}
prints:
0: h
1: e
2: l
3: l
4: o
5: #゚
7: Д゚
fatal error: Can't form a Character from an empty String
// and emits BAD_INSTRUCTION exception
As you can see range!.startIndex never matches to the character boundaries, and the for loop run out the string. That's why you see the exception.
In theory, since String is considered as "Collection of Characters" in Swift, "゚Д゚" should not be a substring of "hello#゚Д゚".
I think .rangeOfString() uses NSString implementation which treats string as a sequence of unichar. I don't know this should be considered as a bug or not.
Try this:
func search<C: CollectionType where C.Generator.Element: Equatable>(col1: C, col2: C) -> C.Index? {
if col2.startIndex == col2.endIndex {
return col1.startIndex
}
var col1Ind = col1.startIndex
while col1Ind != col1.endIndex {
var ind1 = col1Ind
var ind2 = col2.startIndex
while col1[ind1] == col2[ind2] {
++ind1; ++ind2
if ind2 == col2.endIndex { return col1Ind }
if ind1 == col1.endIndex { return nil }
}
++col1Ind
}
return nil
}
Searches for the first instance of the col2 sequence in col1. If found, returns the index of the start of the sub-sequence. If not found, returns nil. If col2 is empty, returns the startIndex of col1.

Resources