Consider the following code:
enum MyErrorType:ErrorType {
case BadTimes
}
var mightHaveAValue: String?
do {
if let value = mightHaveAValue {
// do stuff with value
} else {
throw MyErrorType.BadTimes
}
// do stuff with NSFileManager using mightHaveAValue which might throw
} catch {
// handle error
}
...in which I have a large do/try/catch block. In this instance the error handling will be the same, whether mightHaveAValue is empty or something bad happens with NSFileManager later on. So it makes sense to re-use the error handling code.
Is this the cleanest approach going in Swift2, or is there some way I can automatically throw/catch on unwrapping an optional with no value?
It looks ok, but it's even better with guard let instead of if let because it lets you use the unwrapped value in the main do block instead of having to work inside an if let branch. You can also use several catch branches to handle different error types.
do {
guard let value = mightHaveAValue else {
throw MyErrorType.BadTimes
}
// do stuff with value
} catch let error as MyErrorType {
// handle custom error
} catch let error as NSError {
// handle generic NSError
}
There is no automatic way to handle unwrapping optionals, you have to use one of the many known ways: if let, guard let, nil coalescing, etc.
Maybe just use an extension like this 🤔
extension Optional {
func throwing() throws -> Wrapped {
if let wrapped = self {
return wrapped
} else {
throw NSError("Trying to access non existing value")
}
}
}
Related
I need to verify that a certain call is not made, when a previous method call throws an Exception.
// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
// WHEN
sut.live()
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
Problem with this code, it fails because of the Exception thrown and not because of the failed verification.
I understand that your WHEN block will always throw an exception.
In that case you have multiple options from my point of view:
Simple plain Kotlin. Wrap the WHEN block with a try-catch block, e.g. like this:
// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
// WHEN
var exceptionThrown: Boolean = false
try {
sut.live()
} catch(exception: NotHungryException) {
// Maybe put some assertions on the exception here.
exceptionThrown = true
}
assertTrue(exceptionThrown)
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
For a bit nicer code, you can use JUnit5 API's Assertions. assertThrows will expect an exception being thrown by a specific piece of code. It will fail the test, if no exception is thrown. Also it will return the thrown exception, for you to inspect it.
import org.junit.jupiter.api.Assertions
// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
// WHEN
val exception = Assertions.assertThrows(NotHungryException::class.java) { sut.live() }
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
If you're using Kotest you can use the shouldThrow assertion. Which also allows you to retrieve the thrown exception and validate its type.
import io.kotest.assertions.throwables.shouldThrow
// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
// WHEN
val exception = shouldThrow<NotHungryException> { sut.live() }
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
I had similar issue and found that my method is not surrounded by try catch. This mean the method will always throw exception.
Test
The unit test to verify the result when the following method is called while stubbing it with predefine Exception
#Test
fun returnSearchError() {
every { searchService.search(query) }.throws(BadSearchException())
val result = searchRepository.search(query)
assertEquals(SearchStates.SearchError, result)
}
Faulty code
fun search(query: String): SearchStates {
val result = searchService.search(query) // No try catch for the thrown exception
return try {
SearchStates.MatchingResult(result)
} catch (badSearchException: BadSearchException) {
SearchStates.SearchError
}
}
Refactored it to
fun search(query: String): SearchStates {
return try {
val result = searchService.search(query)
SearchStates.MatchingResult(result)
} catch (badSearchException: BadSearchException) {
SearchStates.SearchError
}
}
I want to implement a different error handling approach in a project without chaining exceptions.
To make it simple as possible, I am tend to write my own basic either-like model.
class Either<F, T> {
final F failure;
final T value;
const Either(this.failure, this.value);
Object check (){
if (failure != null) return failure;
return value;
}
}
I am concerning about returning the type Object, is there any problem or considerations with that in Dart or any other language?
Edit:
or returning dynamic type...
dynamic check(){
if (failure != null) return failure;
return value;
}
I think in your case, it's kind of a wired implementation. The question is, what do you want to do with the actual implementation ? Do you want to replace an if else that will appear over and over? In that case, what would you do if you have to handle the error (failure) ? I think a better approach is to use functions as parameters. Here's a short suggestion.
class Either<T, F> {
T value;
F fail;
Either(this.value, this.fail);
void check(success(T value), {failure(F fail)}) {
if (fail != null && failure != null) {
failure(fail);
} else if (value != null) {
success(value);
}
}
}
class SomeClass {
void checkTheImplementation() {
Either<String, Error> maybeString = Either("testing", null);
// if you don't want to handle the error.
maybeString.check((value) => print(value));
// if you want to handle the error
maybeString.check((value) => print(value), failure: (err) {
print(err.toString());
});
}
}
I have looked over and decided to go with baihu92's either_type way. It's much more clear and comprehensible than either in the dartz package. Here is my implementation:
and the usage is like:
Usually we will pass an object to #synchronized() block for unique reference. for example,
+(id)sharedDBHandler
{
#synchronized (self) {
if (sDBHandler == nil) {
sDBHandler = [self new];
}
}
return sDBHandler;
}
what happens if we pass nil to it?
It doesn't #synchronize() at all. No locks taken. No-op. Undefined behavior.
Perfectly valid question, btw, regardless of whether the code is antiquated and no longer the correct means of generating a singleton.
From the github repository. While not a documented claim, breaking this policy would cause compatibility hell.
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
assert(data);
data->mutex.lock();
} else {
// #synchronized(nil) does nothing
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: #synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
return result;
}
Where:
BREAKPOINT_FUNCTION(
void objc_sync_nil(void)
);
I am trying to convert this Objective-C block into Swift:
[self.client downloadEntity:#"Students" withParams: nil success:^(id response) {
// execute code
}
failure:^(NSError *error) {
// Execute code
}];
This is my code in Swift, but the syntax seems to be a bit off:
client.downloadEntity("Students", withParams: nil, success: {(students: [AnyObject]!) -> Void in
print("here")
}, failure: { (error: NSError!) -> Void! in
print ("here")
}
This is giving me a few compilation errors:
Value of 'AnyObject' has no member 'downloadEntity'
It is complaining about the lack of commas (,) right after the failure part of the code
Try this:
client.downloadEntity("Student", withParams: nil,
success: { (responseObj) -> Void in
print("success: \(responseObj)")
},
failure: { (errorObj) -> Void in
print("treat here (in this block) the error! error:\(errorObj)")
})
You need to switch to the new Swift error syntax, and you can also using trailing closures. I had to use a bool for the example to show how you would call your success closure, or you would throw an error.
var wasSuccessful = true // This is just here so this compiles and runs
// This is a custom error type. If you are using something that throws an
// NSError, you don't need this.
enum Error:ErrorType {
case DownloadFailed
}
// Hopefully you have control over this method and you can update
// the signature and body to something similar to this:
func downloadEntity(entityName: String, success: ([AnyObject]) -> Void) throws {
let students = [AnyObject]()
// download your entity
if wasSuccessful {
// Call your success completion handler
success(students)
}
else {
throw Error.DownloadFailed
}
}
When you have a function that can throw an error, you need to call it with try inside a do/catch block.
// Calling a function that can throw
do {
try downloadEntity("Students") { students in
print("Download Succeded")
}
}
catch Error.DownloadFailed {
print("Download Failed")
}
// If you are handling NSError use this block instead of the one above
// catch let error as NSError {
// print(error.description)
// }
I know this is probably a simple queston, I would like to return the value of currentLocGeoPoint and return the array of Objects which is of type PFObject.
Tried to save it as a global variable, but it doesn't work because it is asynchronous and doesn't take a value yet. Returns empty.
Tried to return currentLocGeoPoint and changed Void in to PFGeoPoint in. Gives error: PFGeoPoint is not convertible to 'Void'
So I'm not sure how I can fetch the variable currentLocGeoPoint.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if (error != nil) {
println("Error:" + error.localizedDescription)
//return
}
if placemarks.count > 0 {
let pm = placemarks[0] as CLPlacemark
self.displayLocationInfo(pm)
currentLoc = manager.location
currentLocGeoPoint = PFGeoPoint(location:currentLoc)
var query = PFQuery(className:"Bar")
query.whereKey("BarLocation", nearGeoPoint:currentLocGeoPoint, withinMiles:10)
query.limit = 500
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if objects != nil {
} else {
println("error: \(error)")
}
}
} else {
println("error: \(error)")
}
})
}
I don't understand the notion of "I want to return currentLocGeoPoint". Return it to what? You're in a CLLocationManagerDelegate method, so there's no one to return it to.
What you could do, though, is, when the request is done (i.e. within this closure), call some other function that needed the currentLocGeoPoint. Or you could update the UI to reflect the updated information (make sure to dispatch that update to the main thread, though). Or, if you have other view controllers or model objects that need to know about the new data, you might post a notification, letting them know that there is an updated currentLocGeoPoint. But within this method, there's no one to whom you would "return" the data.
You could assign it to a stored property of your class. Just use
self.<property> = currentLocGeoPoint