Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to call block on Optional #20

Closed
wants to merge 1 commit into from
Closed

Add ability to call block on Optional #20

wants to merge 1 commit into from

Conversation

DenTelezhkin
Copy link
Contributor

Hey!

I really like then approach and wanted to extend it for optionals. Feature implemented in this PR is different from current Then, however similar in ideology.

It allows calling any custom block of code on optional, if optional contains .Some. Most common case for this would be [weak self] in various kinds of completion blocks, however there are a lot more cases where you can use this approach.

For example, let's say we need to use weak self, however pass self somewhere else as unwrapped optional, like this:

self.doSomethingWithCompletion { [weak self] result in
    self?.parseResult(result, receivedFrom: self!)
    self?.doSomething()
}

This would require multiple optional unwrappings and possibly even force unwraps. Another way to do this is to unwrap with guard:

self.doSomethingWithCompletion { [weak self] result in
    guard let strongSelf = self else { return }
    strongSelf.parseResult(result, receivedFrom: strongSelf)
    strongSelf.doSomething()
}

Unwraps are gone, however we introduced new variable for self, which is not really convenient.
Meet Then from this PR:

self.doSomethingWithCompletion { [weak self] result in
    self.then {
        $0.parseResult(result, receivedFrom: $0)
        $0.doSomething()
    }
}

@devxoul
Copy link
Owner

devxoul commented Feb 4, 2016

Why not use flatMap?

self.doSomethingWithCompletion { [weak self] result in
    self.flatMap {
        $0.parseResult(result, receivedFrom: $0)
        $0.doSomething()
    }
}

Or you can unwrap self by using backtick(`):

self.doSomethingWithCompletion { [weak self] result in
    guard let `self` = self else { return }
    self.parseResult(result, receivedFrom: self!)
    self.doSomething()
}

@DenTelezhkin
Copy link
Contributor Author

You can't use flatMap for two reasons:

  1. It warns about result not being used
  2. It confuses Swift compiler about return value of a closure, in my project at least it shows compiler error:
 Cannot invoke 'flatMap' with an argument list of type '(@noescape (...) throws -> _?)'

If i try to workaround flatMap, it still does not work:

_ = self.flatMap {
    $0.doSomething()
}
Generic parameter 'U' could not be inferred

You can try this yourself.

As for guarding self, as i said, [weak self] is not the only application, here's for example another common one:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        (segue.destinationViewController as? ChooseContenderViewController).then {
            $0.delegate = self
// Some more code on ChooseContenderViewController referenced as $0
        }
    }

Here i am completely skipping creating new variable via if let, and casting controller in type-safe way.

@devxoul
Copy link
Owner

devxoul commented Feb 4, 2016

I'm not sure. Why should we use then() instead of optional binding?

These are the more simple, reasonable, beautiful and extensible:

self.doSomethingWithCompletion { [weak self] result in
    guard let `self` = self else { return }
    self.parseResult(result, receivedFrom: self!)
    self.doSomething()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    switch segue.destinationViewController {
    case let viewController as ChooseContenderViewController:
        // do something with ChooseContenderViewController

    case let viewController as OtherViewController:
        // do something with OtherViewController

    default:
        break
    }
}

I think Then is not a good solution for optional binding but a world most elegant solution for initializing properties with instance initialization code.

@DenTelezhkin
Copy link
Contributor Author

Ok, no problem, it's up to you to decide framework's future.

I am closing this PR then, thanks for discussion.

@devxoul
Copy link
Owner

devxoul commented Feb 5, 2016

Thanks for your time 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants