How to catch exception when use NSExpression (swift 3) - exception

import UIKit
func calculatorFromString(colculation:String)->Double{
let mathExpression = try NSExpression(format: colculation)
let mathValue = mathExpression.expressionValue(with: nil, context: nil) as? Double
return mathValue!
}
calculatorFromString(colculation: "5*(1+4)")
when I set colculation equal "5*(1+4)))", this is a error and I dont know how to catch exception. Thank you!

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html
pseudo Code
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}
hope it's help you
do{
try(calculatorFromString(colculation: "5*(1+4)"))
}catch {
calculatorFromString(colculation: "\(5 * (1 + 4))")
}

Related

How to use data decoded from JSON in SwiftUI

Problem
The data is successfully decoded from Reddit’s api and put into the variable theUser inside the .onAppear {…}, but when I try to use it I keep getting nil values.
Code
struct ContentView: View {
#State var didAppear = false
#State var theUser = getNilUser()
var body: some View {
Text("User Profile")
Text(theUser.data.subreddit.display_name_prefixed ?? "No name found")
.onAppear(perform: {
theUser = getUser(withName: "markregg")
})
}
func getUser(withName username: String) -> user {
if !didAppear {
if let url = URL(string: "https://www.reddit.com/user/\(username)/about.json") {
do {
let data = try Data(contentsOf: url)
do {
let decodedUser = try JSONDecoder().decode(user.self, from: data)
return decodedUser
} catch {
print(error)
}
} catch {
print(error)
}
}
didAppear = true
}
return getNilUser()
}
}
Edit: I’m very new to this so if I made a stupid mistake I’m sorry
You can't get JSON data like that. You have to execute a HTTP request using the URLSession class in order to get the data and parse it.
let username = "markregg"
let url = URL(string: "https://www.reddit.com/user/\(username)/about.json")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
} else if let data = data {
do {
let decodedUser = try JSONDecoder().decode(User.self, from: data)
} catch {
print(error)
}
} else {
print("Request failed")
}
}.resume()
Another thing to note is that URLSession methods are asynchronous. In simple terms it means they take some time to execute and return the result. So you can't use a simple return statement like return decodedUser to get the result right away. Look into how to use URLSession more.

JSON return nil check?

struct AltWX: Decodable {
var raw: String
}
typealias AltMetarDecode = [String: AltWX]
do
{
let aero = try decoder.decode(AltMetarDecode.self, from: data)
DispatchQueue.main.async {
if self.DownloadOrderCode == 3
{
if let Ab = aero[ICAO1]
{
self.Alternate1Metar.text = Ab.raw
UserDefaults.standard.set(Ab.raw, forKey: "MetarCodeAlt1")
}
}
...
The above code accesses a Json like this:
"xxxx": { "raw": "Test"
so Ab.raw would print Test
How can I add an error check to see if ICAO1 exists and also if Ab.raw exists, and if any values are nil return something? I read the usual catch responses to Json but not sure how to format it for this case specifically especially that i have a lot of order codes and each has to be checked separately.
This checks if ICAO1 exists and raw is empty
if let raw = aero["ICAO1"]?.raw, raw.isEmpty {
}
Please name variables lowercased according to the naming convention.
I think you want a do try catch block for this.
enum ContentError: Error {
case missingICAO1
case missingRaw
case orderCodeError
}
// not sure of the return types from the decode block ???
func setValues(values: AltMetarDecode) throws {
guard self.DownloadOrderCode == 3 else { throw ContentError.orderCodeError }
guard let Ab = values[ICA01] else { throw ContentError.missingICA01 }
guard Ab.raw != nil else { throw ContentError.missingRaw }
self.Alternate1Metar.test = Ab.raw
UserDefaults.standard.set(Ab.raw, forKey: "MetarCodeAlt1")
}
do {
let aero = try decoder.decode(AltMetaDecode.self, from data)
try DispatchQueue.main.async {
setValues(values: aero)
}
} catch {
print(error)
}
Setting up a function to throw errors may not be the most code efficient way, but to me it makes the code clear and readable.

SwiftHttp + JSONDecoder

I'm try to parse a json response from a server like this
HTTP.GET(ServerPatientApi.SPLASH, parameters: nil) { response in
if let error = response.error {
listener.onException(error)
return;
}
DispatchQueue.main.async (execute: {
let res = try decoder.decode(PatientSplashModel.self, from: response.data)
listener.onSplashLoaded()
})
}
But I'm receiving the error below:
Invalid conversion from throwing function of type '() throws -> ()' to non-throwing function type '#convention(block)
at the block:
DispatchQueue.main.async (execute: {
let res = try decoder.decode(PatientSplashModel.self, from: response.data)
listener.onSplashLoaded()
})
I think the error caused by:
PatientSplashModel.self
how to fix this?
thanks
The error is a bit misleading, you have to wrap the try statement in a do catch block
DispatchQueue.main.async {
do {
let res = try decoder.decode(PatientSplashModel.self, from: response.data)
listener.onSplashLoaded()
} catch { print(error) }
}

Return variable specified inside closure - Swift [duplicate]

This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 5 years ago.
I am trying to get a string out from an external JSON file, which is on a web server, and it gets it successfully, but it is inside a closure where it gets the value, and I need to get it outside so I can return it with the variable returnip How do I do this?
func getJsonFromUrl() -> String {
let URL2 = "https://url.com/asd.php";
let url = URL(string: URL2)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error as Any)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let ips = parsedData["ip"] as! String
print("The IP is: " + ips) //Prints the value correctly
var returnip = ips //The value that I want to return, that does not go outside this closure
} catch let error as NSError {
print(error)
}
}
}.resume()
return returnip //Does not return anything
}
Thanks
You cannot return from an asynchronous function and a return statement inside a closure only returns from the closure itself.
You need to use a completion handler instead. Also, don't use force unwrapping of optionals/force casting optionals when parsing a network response.
func getJsonFromUrl(name: String, completion: #escaping (String?)->()) {
//use name variable just as you would in a normal function
let URL2 = "https://url.com/asd.php"
let url = URL(string: URL2)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error as Any)
completion(nil)
} else {
do {
guard let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] else { completion(nil); return }
guard let ips = parsedData["ip"] as? String else {completion(nil); return }
print("The IP is: " + ips) //Prints the value correctly
completion(ips)
} catch let error as NSError {
print(error)
completion(nil)
}
}
}.resume()
}
Then you can call it like this:
getJsonFromUrl(name: "Input", completion: { ips in
print(ips)
//you can only use the value inside the closure of completion
})

Unexpected non-void return value in void function - JSON Data from dataTask(with: URL) - (Swift 3.0)

I'm building an iOS app in Swift 3 that's supposed to communicate with a JSON Rest Api that I'm also building myself. The app will get all sorts of content from the Api, but for now all I need it to do is check the availability of the Api through a handshake function.
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
if jsonResult["response"] as! String == "Welcome, come in!" {
print("************ RESPONSE IS: ************")
print(jsonResult)
return
} else {
return
}
} catch {
print("************ JSON SERIALIZATION ERROR ************")
}
}
}
}
task.resume()
This is the dataTask I've set up and it runs just fine (When I print the jsonResult, I get the "Welcome!" message as expected. The problem is that I want my handshake function to return true or false (So that I can give an alert if the case is false.) When I try to set up a return true or false within the if-statement, I get the error: Unexpected non-void return value in void function.
My question is: How do I return the data out of the dataTask so that I can perform checks with it within my handshake function? I'm very new to Swift so all help is appreciated :)
Below is the entire class:
import Foundation
class RestApiManager: NSObject {
var apiAvailability:Bool?
func handshake() -> Bool {
let url = URL(string: "https://api.restaurapp.nl/handshake.php")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
if jsonResult["response"] as! String == "Welcome, come in!" {
print("************ RESPONSE IS: ************")
print(jsonResult)
return true
} else {
return false
}
} catch {
print("************ JSON SERIALIZATION ERROR ************")
}
}
}
}
task.resume()
}
}
Because you're using an asynchronous API, you can't return the bool from your handshake function. If you want to show an alert in the false case, you would replace the return false with something like:
DispatchQueue.main.async {
self.showAlert()
}
Technically you could make the handshake function pause until the network stuff was done, and return the bool, but that defeats the purpose of being asynchronous, and it would freeze your app's UI during the network activity, so I doubt that's what you want to do.