How to write a template function that handle do catch - swift

I want to write a template function that handle do catch. It may look like this
func handleMethod(methodNeedToHandle) -> result: notSureType{
var result
do {
let response = try handleMethod
result = response
return result
} catch let error as someObjectError{
result = error
return result
}
}
Then you can use it like
let catchResult = handleMethod(method(x: something, y: something))
Thank you guys help me a lot, I get working code below
func handleDoTryCatch<T>(closure:() throws -> T) -> Any {
do {
let result = try closure()
return result
} catch let error {
return error
}
}

You could use a generic function that takes a closure and returns a tuple.
Something like:
func handle<T>(closure:() throws -> T) -> (T?, Error?) {
do {
let result = try closure()
return (result, nil)
} catch let error {
return (nil, error)
}
}
This will define a function that takes a closure that calls the method that can throw. It the returns a tuple with the expected return type and something that conforms to the Error protocol.
You would use it like this:
let result: (Void?, Error?) = handle { try someFunc() }
let result2: (Int?, Error?) = handle { try someOtherFunc(2) }
someFunc and someOtherFunc are just examples and their signatures would be:
func someFunc() throws {}
func someOtherFunc(_ param: Int) throws -> Int {}

This is the function I managed to come up with:
// Your error cases
enum Errors: Error {
case someErrorCase
}
// Function to test another function
func doTryCatch<T>(for function: () throws -> T) {
do {
let returnValue = try function()
print("Success! The return value is \(returnValue)")
} catch {
print("Error! The error reason was \"\(String(describing: error))\"")
}
}
// Function to test
func failingFunction() throws -> Int {
throw Errors.someErrorCase // <-- Comment this to not recieve an error (for testing)
return 5 // Will return 5 if the error is not thrown
// Failure: Error! The error reason was "someErrorCase"
// Success: Success! The return value is 5
}
// Perform the test
doTryCatch(for: failingFunction) // <-- Very easy to test, no closures to write!
Hope this helps with your debugging! :)

The closest I could get to what you probably want is the following:
(Swift Playground code:)
func handleMethod(_ f: #autoclosure () throws -> Void) -> Error? {
do {
try f()
} catch let err {
return err
}
return nil
}
enum HelloError: Error {
case tooShort
}
func hello(_ what: String) throws {
guard what.count > 0 else { throw HelloError.tooShort }
print ("Hello \(what)!")
}
// use like this:
// let err = handleMethod(try hello("World")) // err == nil
// let err = handleMethod(try hello("")) // err == HelloError.tooShort
//
print ("* hello(\"World\") -> \(String(describing: handleMethod(try hello("World"))))")
print ("* hello(\"\") -> \(String(describing: handleMethod(try hello(""))))")
This will produce the following output:
Hello World!
* hello("World") -> nil
* hello("") -> Optional(__lldb_expr_3.HelloError.tooShort)
Consider just using do/catch as George_E recommends. It's a good advice. But if you need this function, than this snipped hopefully gives you a starting point.

Related

Can I do something not `transfrom` in `map` and `flatMap` function?

Is Map function of Optional in Swift just used to transform?
If I want do something just Optional has some value, Can I Use map function? if not, why?
According to apples examples, we used map like this
let possibleNumber: Int? = Int("42")
possibleNumber.map { $0 * $0 }
Can I use it like this? : (If it's not proper, how to explain it)
func setImage(with data: Data?) {
data.flatMap { UIImage(data: $0) }
.map { imageView.image = $0 }
}
Furthermore map function should return a value, but why this function does not have any warning about not used of result ( such as result of call map{...} is unused ) ?
You certainly can do it, it's just not very conventional. When people see map, they have a pre-conceived expectation that it'll be doing a transformation. You're violating that expectation, but there's nothing technically "wrong" about it.
Personally, I prefer using this extension:
extension Optional {
/// An enum used to ensure that `ifNone` is never called before `ifSome`.
enum IfSomeResult {
case some
case none
func ifNone(_ closure: () throws -> Void) rethrows -> Void {
switch self {
case .some: return
case .none: try _ = closure()
}
}
}
#discardableResult
func ifSome(then closure: (Wrapped) throws -> Void) rethrows -> IfSomeResult {
if let wrapped = self {
try _ = closure(wrapped)
return IfSomeResult.some
}
else {
return IfSomeResult.none
}
}
func ifNone(then closure: () throws -> Void) rethrows -> Void {
if case nil = self { try _ = closure() }
}
}
And writing code like:
data.flatMap { UIImage(data: $0) }
.ifSome { imageView.image = $0 }
Why doesn't it warn about an unused value?
The closure is inferred to return Void (the empty tuple type, whose only value is the empty tuple, ()). The compiler never emits warnings about Void values being unused`. Here's an example:
Optional(123).map { _ in () }

Throwing errors from closure

I have this piece of code in my app:
func saveContact2(contact: String) throws {
let contactStore = CNContactStore()
contactStore.requestAccess(for: .contacts, completionHandler: {(granted, error) in
if granted && error == nil {
//...
} else {
if !granted {
throw contactErrors.contactAccessNotGranted(["Error","Access to Contacts is not granted."])
}
}
})
}
I'd like to throw all errors raising in closure to calling function.
Compiler shows error:
Invalid conversion from throwing function of type '(_, _) throws -> ()' to non-throwing function type '(Bool, Error?) -> Void'
Could anyone help me please with the right syntax?
You cannot throw errors from an #escaping closure that is called asynchronously. And this makes sense because your app has carried on with its execution and there’s no where to catch the error.
So, instead, adopt completion handler pattern yourself:
func saveContact2(_ contact: String, completion: #escaping: (Result<Bool, Error>) -> Void) {
let contactStore = CNContactStore()
contactStore.requestAccess(for: .contacts) { (granted, error) in
guard granted else {
completion(.failure(error!)
return
}
//...
completion(.success(true))
}
}
And then you’d call it like:
saveContact2(contactName) { result in
switch result {
case .failure:
// handler error here
case .success:
// handle confirmation of success here
}
}
If you’re using an old compiler that doesn’t have the Result type, it’s basically:
enum Result<Success, Failure> where Failure: Error {
case success(Success)
case failure(Failure)
}

Using Do/Catch in Swift

I am working on an app and want to get data back from a function. However sometimes data is missing or is different from the kind of that I want to retrieve. I am new to Swift and I can't find a way to write a function that does a little bit of processing and returns this data. When this data is missing, the function should give back a string "Not Found". Like this:
func processData(data:String) {
do {
//processing
var result = processedData
} catch {
var result = "Not Found"
}
return result
}
It would be very nice if somebody could help me.
You should check if the result is nil.
func processData(data: String?) -> String {
guard let result = data else {
return "Not Found"
  }
return result
}
The most concise way of doing it would be using the guard-let construct:
func processData(data: String?) -> String {
// Assuming getProcessedData(:) returns your processed data
guard let result = getProcessedData(data) else {
return "Not found"
}
return result
}
Also, your function is missing a return type. You must specify the return type like -> TYPE in all functions that return some value.
Those answer were written till mine are right. There is one way: with handler check get result and use by your point.
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?, completionHandler: #escaping (_ result: String? , _ error: Error?) -> Void ) {
guard let data = data else {
// Data is missing
throw nil, Errors.noData
}
// Do other things, and throw if necessary
result = data
return result, nil
}
// example of calling this function
process(data: "A data to process"){(result, error) -> Void in
//do any stuff
/*if error == nil {
}*/
}
A good practice in swift would be to use correctly the throws errors
This is an example inspired from yours :
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?) throws -> String {
guard let data = data else {
// Data is missing
throw Errors.noData
}
// Do other things, and throw if necessary
result = data
return result
}
do {
try process(data: "A data to process")
} catch {
print("An error occurred: \(error)")
}
You can try this code as is in a Swift Playgound
Your function needs to be explicit about returning something with e.g. -> String Also do-catch is for methods that can throw an error. It seems like you need to take a look at how to use optionals. Optionals can have a value or they can have no value.
fun processData(data: String) -> String {
var result: String?
// Do some processing and assign the result to result variable
guard let result = result else { return "Not Found" }
return result
}

Rejecting a the returned promise inside a then block

Say I have two promises I want to combine with a when(resolved:). I want to reject the promise if there was a problem with the first promise, but resolve otherwise. Essentially, this is what I want to do:
func personAndPetPromise() -> Promise<(Person, Pet?)> {
let personPromise: Promise<Person> = ...
let petPromise: Promise<Pet> = ...
when(resolved: personPromise, petPromise).then { _ -> (Person, Pet?) in
if let error = personPromise.error {
return Promise(error: error) // syntax error
}
guard let person = personPromise.value else {
return Promise(error: myError) // syntax error
}
return (person, petPromise.value)
}
}
such that externally I can do something like this:
personAndPetPromise().then { person, pet in
doSomethingWith(person, pet)
}.catch { error in
showError(error)
}
The problem lies within the the then { _ in block in personAndPetPromise. There's no way that method can return both a Promise(error:) and a (Person, Pet?).
How else can I reject the block?
The problem is that there are two overloads of the then function:
public func then<U>(on q: DispatchQueue = .default, execute body: #escaping (T) throws -> U) -> Promise<U>
public func then<U>(on q: DispatchQueue = .default, execute body: #escaping (T) throws -> Promise<U>) -> Promise<U>
The first one's body returns a U and causes then to return Promise<U>.
The second one's body returns a Promise<U> and causes then to return Promise<U>.
Since in this case we want to return an error or a valid response, we're forced to use the second overload.
Here's a working version. The main difference is I changed it from -> (Person, Pet?) to -> Promise<(Person, Pet?)>:
func personAndPetPromise() -> Promise<(Person, Pet?)> {
let personPromise: Promise<Person> = ...
let petPromise: Promise<Pet> = ...
when(resolved: personPromise, petPromise).then { _ -> Promise<(Person, Pet?)> in
if let error = personPromise.error {
return Promise(error: error)
}
guard let person = personPromise.value else {
return Promise(error: myError)
}
return Promise(value: (person, petPromise.value))
}
}
Another way to do the same thing is by throwing the error rather than attempting to return it:
func personAndPetPromise() -> Promise<(Person, Pet?)> {
let personPromise: Promise<Person> = ...
let petPromise: Promise<Pet> = ...
when(resolved: personPromise, petPromise).then { _ -> (Person, Pet?) in
if let error = personPromise.error {
throw error
}
guard let person = personPromise.value else {
throw myError
}
return (person, petPromise.value)
}
}

"Missing return in a closure expected to return 'SomeType'" error in .map

I have the fallowing code:
struct AInt {
var aInt: Int
}
struct ADouble {
var aDouble: Double
static func convert(aInt: AInt) throws -> ADouble {
return ADouble(aDouble: Double(aInt.aInt))
}
}
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
}
// ^^^ error here: Missing return in a closure expected to return 'ADouble'
}
}
let aInts = [AInt(aInt: 2), AInt(aInt: 3)]
let b = B()
do {
print(try b.doAction(aInts))
}
catch {}
When i'm trying to convert [AInt] to [ADouble] in .map using function that can throw error, i get this error:
Missing return in a closure expected to return 'ADouble'.
Well, i decided to add return statement in the end of .map like this:
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
Error disappear, but when i print try b.doAction(aInts) on same aInts array, i get this: [ADouble(aDouble: 2.2), ADouble(aDouble: 2.2)], i.e. it prints my ADouble(aDouble: 2.2) that i set manually. Obviously, it's not what i want, so then i try to add return before try ADouble.convert(aInt) like this:
return aInts.map { aInt in
do {
return try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
And now i get right result: [ADouble(aDouble: 2.0), ADouble(aDouble: 3.0)]. But this code still doesn't work without return statement in the end of the .map. Any ideas how to get rid of it?
The map() method is declared as
#rethrows public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
which means (if I understand it correctly) that the transform can
either return a value or throw an error (and this will be
forwarded to the caller).
This compiles and works as expected:
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return try aInts.map { aInt in
return try ADouble.convert(aInt)
}
}
}
An error thrown from ADouble.convert(aInt) will be forwarded to
the caller of map() and from there to the caller of doAction().