swiftswift-optionals

Swift Extension - Optional


I'm trying to extend optionals into something readable, and achieved this so far:

@discardableResult
    func isNotNil(_ handler: (Wrapped) -> Void) -> Optional {
        switch self {
        case .some(let value):
            handler(value)
            return self
        case .none:
            return self
        }
    }
    
    @discardableResult
    func isNil(_ handler: () -> Void) -> Optional {
        switch self {
        case .some:
            return self
        case .none:
            handler()
            return self
        }
    }

So that I can call my functions on an optional such as:

viewModel?.title.isNotNil { _ in
   //do something
}.isNil {
  //handle error
}

The problem is, I want to reuse these functions to return specific types, which I'm not able to achieve or am missing something out. For example:

let vm: MyViewModel = dataSource?.heading.isNotNil {
  return MyViewModel(title: $0.title, subtitle: $0.subtitle)
}

I've been brainstorming on this and would love some help around this.

Thanks!


Solution

  • What you're doing in your example will raise errors. It boils down to

    let vm: MyViewModel
    if let heading = dataSource?.heading  {
       _ = MyViewModel(heading.title, heading.subtitle)
      vm = heading
    }
    

    So you're trying to assign heading to vm (which I am assuming are of different types) and you just construct and drop the MyViewModel you construct in the closure

    What would be a better option is something along these lines:

    func mapOptionalOrNot<T>(notNil: (Wrapped) -> T, isNil: () -> T) -> T {
        switch self {
        case .some(let value):
            return notNil(value)
        case .none:
            return isNil()
        }
    }
    

    And you could of course give both function default arguments so you can leave them out.

    With Swift 5.3s new multi closures you could do something like

    let vm: MyViewModel = dataSource?.heading.mapOptionalOrNot { value in
        // Map if we have a value
        return MyViewModel(title: value.title, subtitle: value.subtitle)
    } isNil: {
        // Map if we don't have a value
        return MyViewModel(title: "Empty", subtitle: "Empty")
    }