Returning value for function that throws - swift

I've got a pretty simple question but I could only find a similar answer in C++ thread. Compiler complains on getUserFromServer function stating that it requires return value even though it can catch an exception. It is obvious WHY it asks for return value but I'm not sure how to handle the situation properly.
One way is to create some sort of dummy user and return it but it doesn't sound any good. Another way is by making return type Optional but it's just moving responsibility for nil-checks to another level, which is probably not a good idea. Any help would help.
Here's a setup to simulate behaviour I expect in real code.
enum TestError: Error {
case JustError
}
class User {}
class ServerClient {
func getUser(really: Bool) throws -> User {
var uza: User?
if really {
uza = User()
}
guard let user = uza else {
throw TestError.JustError
}
return user
}
}
func getUserFromServer() -> User {
let client = ServerClient()
let user: User
do {
user = try client.getUser(really: true)
return user
} catch TestError.JustError {
print("just an error occured")
} catch {
print("something terrible happened")
}
} //Error: missing return in a function

So imagine I'm a the caller, and I write this line of code:
let user = getUserFromServer()
print(user)
It fails somehow. Great. What do you want to happen? What should user be? What should print? (There's no right answer here; the question really is what do you want it to be?)
If you want user to be nil, then getUserFromServer should return User?. If you want user to be some default user, then you'll need a way to create that. If you want the caller to not print at all (and instead handle some error), then getUserFromServer() should throw. If you want it to crash, then you need to add a fatalError inside getUserFromServer. These are all valid, but it has to do something, and what that something is, is up to you.
That said, if the question is just advice about what it should be, looking at this code you should probably default to making it an optional unless you need some other behavior. That would be the "normal" thing here since you already "handled" the error.

Related

Handling exceptions in guard blocks

I'm looking for an elegant way of combining guard blocks with do-try-catch semantics in Swift, and haven't been satisfied with my own efforts so far.
For background, I'm getting hold of some necessary data from a function that throws an exception and can return an Optional value. As a concrete example, let's say I'm looking up the most recent item from a TODO list stored on the filesystem. This can legitimately be nil (nothing on the list), or it can thrown an exception (some sort of I/O error accessing the filesystem), so both cases are distinct.
For the rest of the method though, we only care if there is a item to operate on - so this sounds like an ideal case for guard:
func myCoolMethod() {
guard let todoItem = try? fetchItemFromList() else {
// No item to act on, nothing to do
return
}
// rest of function acts on todoItem
...
}
This is indeed fine - until the guard block starts failing when you expect it to succeed, and you'd really like to (if nothing else) log the error message to try and investigate. As such, the try? needs to be replaced by a try to allow the error to be captured, and now we'll need to wrap the guard in a do block:
func myCoolMethod() {
do {
guard let todoItem = try fetchItemFromList() else {
// No item to act on, nothing to do
return
}
// rest of function acts on todoItem
...
}
catch {
// Now we know there was an error of some sort (can specialize the
// catch block if we need to be more precise)
// log error or similar, then...
return
}
}
There are two problems with this that I see:
The do block needs to wrap the whole method (due to the scope of todoItem). This means that the happy-path logic is indented (which is something that guard specifically helps to avoid); but additionally, it means that any errors from that logic will be caught by the catch block, perhaps accidentally. I'd much prefer the do block to only be scoped around the guard.
There's duplication of the "what to do if we have no item" block. In this trivial example it's just a return, but it still pains me a little to have two separate blocks that need to do broadly the same thing (where one just adds a little extra context with the error being available).
I'd like to get as close to this as possible:
func myCoolMethod() {
// `do guard` is made up but would enter the else block either if an exception
// is thrown, or the pattern match/conditional fails
do guard let todoItem = try fetchItemFromList() else {
if let error = error {
// Optional `error` is only bound if the guard failed due to an exception
// here we can log it etc.
}
// This part is common for both the case where an exception was thrown,
// and the case where the method successfully returned `nil`, so we can
// implement the common logic for handling "nothing to act on"
return
}
// rest of function acts on todoItem
...
}
What are my options here?
First, look for errors and deal with them. Then look for existence, and deal with that:
func myCoolMethod() {
// Making this `let` to be stricter. `var` would remove need for `= nil` later
let todoItem: Item?
// First check for errors
do {
todoItem = try fetchItemFromList()
} catch {
todoItem = nil // Need to set this in either case
// Error handling
}
// And then check for values
guard let todoItem = todoItem else {
// No item to act on (missing or error), nothing to do
return
}
// rest of function acts on todoItem
print(todoItem)
}
Or separate the problems into functions. When things get complicated, make more focused functions:
func myCoolMethod() {
// And then check for values
guard let todoItem = fetchItemAndHandleErrors() else {
// No item to act on (missing or error), nothing to do
return
}
// rest of function acts on todoItem
print(todoItem)
}
func fetchItemAndHandleErrors() -> Item? {
// First check for errors
do {
return try fetchItemFromList()
} catch {
// Error handling
return nil
}
}

Is naming a constant within a function the same as the passing argument bad practice?

I am learning the swift programming language. I'm following the "Intro to App Development with Swift" by Apple. In the course I am instructed to make the question argument lowercase.
// The course's answer
func responseTo(question: String) -> String {
let lowerQuestion = question.lowercased()
if lowerQuestion.hasPrefix("where") {
return "To the North!"
} else if lowerQuestion == "where are the cookies?" {
return "In the cookie jar!"
} else {
return "That really depends"
}
}
// My answer
func responseTo(question: String) -> String {
// TODO: Write a response
let question = question.lowercased()
if question.hasPrefix("hello") {
return "Why, hello there"
} else {
return "That really depends"
}
}
The String question is being passed. My way of doing was to make a constant also named question. The course made a constant called lowerQuestion.
Is my way considered bad practice? Could this cause errors in a large scale application?
Thank you for taking the time to look at my question!
The new question constant effectively hides the question parameter, which means that you cannot access the parameter question anymore after the declaration of the question constant.
In this case, you don't need the parameter anymore, so it's fine to do this, but in more large-scale projects, you never know when your requirements are going to change, and when it becomes that you actually need the parameter question later in the method. It is more troublesome for you to change it when that happens.
In addition, having two variables with the same name generally is not a good idea. It is very easy for readers of your code to get confused between them, even if the compiler doesn't.
That's a perfectly valid thing to do! You can also declare variables with the same name if they're in different scopes.
Typically this is okay. But if you had a global variable with the same name, then it can cause mutations. It's probably best practice to be more descriptive with your variable names anyways.
Also, once you assign question = question.toLowerCase(), you will no longer be able to access your parameter's original value.
It's not a bad practice as long as you plan to use the name as you defined it locally and aren't planning on referencing the argument as received. It's especially useful when safely unwrapping an Optional parameter.
For example:
func responseTo(question: String?) -> String {
// Exit early if our parameter is nil
guard let question = question else {
return "What question?"
}
...
}
Another example can be when using a URL (or any failable initializer), or when it's convenient to use the argument converted to some other type:
func process(url: String) {
guard let url = URL(string: url) else {
return // bailing early
}
...
}
func addThree(to number: String) throws {
guard let number = Int(number) else {
throw Error.notANumber
}
return number + 3
}
or when your parameter is the raw value of some enum:
enum Pet: String {
case dog
case cat
case bird
}
var pets = [Pet]()
func add(newPet: String) {
guard let newPet = Pet(rawValue: newPet) else {
return
}
pets.append(newPet)
}

How to generalize form inputs from properties using functional reactiveSwift?

When doing forms with fields i want to send if there is a change i often do
let initialOrChangedName = Signal.merge(
nameChanged.signal,
self.viewDidLoadProperty.signal
.map { _ in nil }
)
where
private let nameChangedProperty = MutableProperty<String?>(nil)
private let viewDidLoadProperty = MutableProperty(())
to get a signal that has fired once on load, so i can use it in a combineLatest when user taps a button that will fire a web request with the form value to server. Since this signal merges it will give all values that change after the initial value, allowing me to send the newest value when user taps the submit button
Usage for this is usually something like
Signal.combineLatest(intialOrChangedName, initialOrChangedAge)
.sample(on:sendButtonTappedProperty.signal)
if values sent nil, i just dont include them in the web request, but i do get the other values if some of them was changed by user.
Since this is a fairly common pattern, i want to generalize it to a single function, for example
let initialOrChangedName = nameChanged.initialOrChangedState(on: viewDidLoadProperty)
I've tried writing it
extension MutableProperty where Value: OptionalProtocol {
public func initialOrChangedState(on viewDidLoadProperty: MutableProperty<Void>) -> Signal<Value?, Error> {
return Signal.merge(self.signal.map(Optional.init),
viewDidLoadProperty.signal.map { _ in nil})
}
}
Which looks good on paper, but will return String?? for the example given, and does not work.
I've also tried writing it as a static function on Signal, but with no luck.
I guess it should be something like this:
extension MutableProperty where Value: OptionalProtocol {
public func initialOrChangedState(on viewDidLoadProperty: MutableProperty<Void>) -> Signal<Value?, Error> {
return self.signal.map({Optional<Value>($0)}).merge(with: viewDidLoadProperty.signal.map({_ in nil}))
}
}
But, whats the point of using viewDidLoadProperty? Actually, if you subscribe to your signal at the end of viewDidLoad(), you don't even need such a property and as a result you wont need that merge() thing and you wont need to extend MutableProperty protocol.
So, all you need to do is something like:
submitButton.reactive.controlEvents(.touchUpInside).observer(on: UIScheduler()).observeValues({ _ in
readInputs()
launchRequest()
})
I might be misunderstanding so forgive me, if I am. But I think something like this might help. I have this method in a library I’ve written.
public func to<T>(_ value: T) -> Signal<T, Error> {
self.map { _ in value }
}
which allows you to do something like this
let voidProperty = MutableProperty(())
let nilStringSignal: Signal<String?, Never> = voidProperty.signal.to(nil)
So then maybe your case could be something like this, which leans a bit on type inference
nameChanged.signal.merge(with: self.viewDidLoadProperty.signal.to(nil))
I know maybe that’s not quite as concise as you want. Working with generics like optionals in signals can sometimes make the type wrangling a bit frustrating 😅

All asynchronous calls succeed or none, how to handle

I'm trying to create an online mobile application and can't figure out the best way to handle functions with multiple asynchronous calls. Say I have a function for example that updates a user in some way, but involved multiple asynchronous calls in the single function call. So for example:
// Function caller
update(myUser) { (updatedUser, error) in
if let error = error {
// Present some error UI to the user
}
if let updatedUser = updatedUser {
// Do something with the user
}
}
// Function implementation
public func updateUser(user: User, completion: #escaping (User?, Error?) -> () {
// asynchronous call A
updateUserTable(user: User) { error in
if let error = error {
completion(nil, error)
} else {
// create some new user object
completion(user, nil)
}
}
// asynchronous call B
uploadMediaForUser(user: User) { error in
if let error = error {
completion(nil, error)
}
}
// asynchronous call C
removeOldReferenceForUser(user: User) { error in
if let error = error {
completion(nil, error)
}
}
// Possibly any additional amount of asynchronous calls...
}
In a case like this, where one function call like updating a user involved multiple asynchronous calls, is this an all or nothing situation? Say for example the updateUserTable() call completes, but the user disconnects from the internet as uploadMediaForUser() was running, and that throws an error. Since updateUserTable() completed fine, my function caller thinks this method succeeded when in fact not everything involved in updating the user completed. Now I'm stuck with a user that might have mismatched references or wrong information in my database because the user's connection dropped mid call.
How do I handle this all or nothing case? If EVERY asynchronous call completed without an error, I know updating the user was a success. If only a partial amount of asynchronous calls succeeded and some failed, this is BAD and I need to either undo the changes that succeeded or attempt the failed methods again.
What do I do in this scenario? And also, and how do I use my completion closure to help identify the actions needed depending on the success or failure of the method. Did all them succeed? Good, tell the user. Do some succeed and some failed? Bad, revert changes or try again (i dont know)??
Edit:
Just calling my completion with the error doesn't seem like enough. Sure the user sees that something failed, but that doesn't help with the application knowing the steps needed to fix the damage where partial changes were made.
I would suggest adding helper enums for your tasks and returned result, things like (User?, Error?) have a small ambiguity of the case when for example both are nil? or you have the User and the Error set, is it a success or not?
Regarding the all succeeded or some failed - I would suggest using the DispatchGroup to notify when all tasks finished (and check how they finished in the end).
Also from you current code, when some request fails it's not clear for which user - as you pass nil, so it might bring difficulties in rolling it back after failure.
So in my point of view something like below (not tested the code, but think you should catch the idea from it) could give you control about the issues you described:
public enum UpdateTask {
case userTable
case mediaUpload
// ... any more tasks you need
}
public enum UpdateResult {
case success
case error([UpdateTask: Error])
}
// Function implementation
public func updateUser(user: User, completion: #escaping (User, UpdateResult) -> ()) {
let updateGroup = DispatchGroup()
var tasksErrors = [UpdateTask: Error]()
// asynchronous call A
updateGroup.enter()
updateUserTable(user: User) { error in
if let error = error {
tasksErrors[.userTable] = error
}
updateGroup.leave()
}
// ... any other similar tasks here
updateGroup.notify(queue: DispatchQueue.global()) { // Choose the Queue that suits your needs here by yourself
if tasksErrors.isEmpty {
completion(user, .success)
} else {
completion(user, .error(tasksErrors))
}
}
}
Keep a “previous” version of everything changed, then if something failed revert back to the “previous” versions. Only change UI once all returned without failure, and if one failed, revert to “previous” version.
EX:
var temporary = “userName”
getChanges(fromUser) {
If error {
userName = temporary //This reverts back due to failure.
}
}

How do I execute code once and only once in Swift?

The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once is of no use if we I can change the value of token! And turning token into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>.
So should we give up on dispatch_once in Swift? Is there a safer way to execute code just once?
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
Static properties initialized by a closure are run lazily and at most once, so this prints only once, in spite of being called twice:
/*
run like:
swift once.swift
swift once.swift run
to see both cases
*/
class Once {
static let run: Void = {
print("Behold! \(__FUNCTION__) runs!")
return ()
}()
}
if Process.arguments.indexOf("run") != nil {
let _ = Once.run
let _ = Once.run
print("Called twice, but only printed \"Behold\" once, as desired.")
} else {
print("Note how it's run lazily, so you won't see the \"Behold\" text now.")
}
Example runs:
~/W/WhenDoesStaticDefaultRun> swift once.swift
Note how it's run lazily, so you won't see the "Behold" text now.
~/W/WhenDoesStaticDefaultRun> swift once.swift run
Behold! Once runs!
Called twice, but only printed "Behold" once, as desired.
I think the best approach is to just construct resources lazily as needed. Swift makes this easy.
There are several options. As already mentioned, you can initialize a static property within a type using a closure.
However, the simplest option is to define a global variable (or constant) and initialize it with a closure then reference that variable anywhere the initialization code is required to have happened once:
let resourceInit : Void = {
print("doing once...")
// do something once
}()
Another option is to wrap the type within a function so it reads better when calling. For example:
func doOnce() {
struct Resource {
static var resourceInit : Void = {
print("doing something once...")
}()
}
let _ = Resource.resourceInit
}
You can do variations on this as needed. For example, instead of using the type internal to the function, you can use a private global and internal or public function as needed.
However, I think the best approach is just to determine what resources you need to initialize and create them lazily as global or static properties.
For anyone who stumbles on this thread... We ran into a similar situation at Thumbtack and came up with this: https://www.github.com/thumbtack/Swift-RunOnce. Essentially, it lets you write the following
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
runOnce {
// One-time code
}
}
I also wrote a blog post explaining how the code works, and explaining why we felt it was worth adding to our codebase.
I found this while searching for something similar: Run code once per app install. The above solutions only work within each app run. If you want to run something once across app launches, do this:
func runOnce() {
if UserDefaults.standard.object(forKey: "run_once_key") == nil {
UserDefaults.standard.set(true, forKey: "run_once_key")
/* run once code */
} else {
/* already ran one time */
}
}
If the app is deleted and re-installed, this will reset.
Use NSUbiquitousKeyValueStore for tracking a value across installs and devices as long as user using same appleID.