RxSwift unwrap optional handy function? - swift

Currently I have created a function unwrapOptional to safely unwrap the optional input in the stream.
func unwrapOptional<T>(x: Optional<T>) -> Observable<T> {
return x.map(Observable.just) ?? Observable.empty()
}
let aOpt: String? = "aOpt"
_ = Observable.of(aOpt).flatMap(unwrapOptional).subscribeNext { x in print(x)}
let aNil: String? = nil
_ = Observable.of(aNil).flatMap(unwrapOptional).subscribeNext { x in print(x)}
let a: String = "a"
_ = Observable.of(a).flatMap(unwrapOptional).subscribeNext { x in print(x)}
// output
aOpt
a
What I want to archive is to create a handy function instead of using flatMap(unwrapOptional), for example
Observable.of(a).unwrapOptional()
Something I tried to do, but it never compiles...
extension ObservableType {
func unwrapOptional<O : ObservableConvertibleType>() -> RxSwift.Observable<O.E> {
return self.flatMap(unwrapOptional)
}
}

You want the unwrapOptional method to only work on observables that have optional type.
So you somehow have to constraint the Element of Observable to conform to the Optional protocol.
extension Observable where Element: OptionalType {
/// Returns an Observable where the nil values from the original Observable are
/// skipped
func unwrappedOptional() -> Observable<Element.Wrapped> {
return self.filter { $0.asOptional != nil }.map { $0.asOptional! }
}
}
Unfortunately, Swift does not define such a protocol (OptionalType). So you also need to define it yourself
/// Represent an optional value
///
/// This is needed to restrict our Observable extension to Observable that generate
/// .Next events with Optional payload
protocol OptionalType {
associatedtype Wrapped
var asOptional: Wrapped? { get }
}
/// Implementation of the OptionalType protocol by the Optional type
extension Optional: OptionalType {
var asOptional: Wrapped? { return self }
}

checkout unwrap at https://github.com/RxSwiftCommunity/RxSwift-Ext :)
or https://github.com/RxSwiftCommunity/RxOptional
For now, you should use RxOptional for your personal needs
However, RxSwift-Ext will be growth exponentially in next 2-3 months :)

RxSwift now supports compactMap(). So, now you can do things like:
func unwrap(_ a: Observable<Int?>) -> Observable<Int> {
return a.compactMap { $0 }
}

Here's a version without needing OptionalType (from https://stackoverflow.com/a/36788483/13000)
extension Observable {
/// Returns an `Observable` where the nil values from the original `Observable` are skipped
func unwrap<T>() -> Observable<T> where Element == T? {
self
.filter { $0 != nil }
.map { $0! }
}
}

Related

how to store away sequence variables with constraints in swift

I wanted to create a "where_non_null" operation that works on any swift sequence - which is easy if you return an array, but obviously that is potentially bad performance wise - because you are forcing the entire sequence to resolve in memory - so I created the following that just goes line by line:
//
// this iterates through the underlying sequence, and returns only the values that are not null
//
public class Not_null_iterator<T> : IteratorProtocol
{
public typealias Element = T
private let next_function : () -> T?
init<T_iterator: IteratorProtocol>( _ source: T_iterator ) where T_iterator.Element == Optional<T>
{
var iterator = source
next_function =
{
while (true)
{
if let next_value = iterator.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
else
{
return nil
}
}
}
}
public func next() -> T? {
next_function()
}
}
//
// a sequence wrapping an underlying sequence, that removes any nulls as we go through
//
public class Not_null_sequence<T > : Sequence
{
private var iterator_creator : () -> Not_null_iterator<T>
init<T_source_sequence : Sequence >( _ source : T_source_sequence ) where T_source_sequence.Element == Optional<T>
{
iterator_creator =
{
Not_null_iterator(source.makeIterator())
}
}
public func makeIterator() -> Not_null_iterator<T>
{
iterator_creator()
}
}
extension Sequence
{
//
// return only the not null values in the sequence without ever resolving more than one item in memory at one time and remove the optionality on the type
//
func where_not_null<T>() -> Not_null_sequence<T> where Element == Optional<T>
{
return Not_null_sequence( self)
}
}
class Where_not_null_tests : XCTestCase
{
public func test_where_not_null()
{
let source = [1, 2, 3, nil, 4]
let checked : [Int] = Array(source.where_not_null())
XCTAssertEqual([1,2,3,4],checked)
}
}
which works great - however I had to define the next() and make_iterator() functions in the constructor, because I couldn't find any type safe way of putting the source into a class level variable.
Is there a way of doing that?
[and yes, I'm aware swift people prefer camel case]
Rather than just using one generic parameter, you'd need two generic parameters. You can't just constrain one generic parameter to say that it has to be some sequence with an element of some Optional. You need another generic parameter to say what the optional's type is:
class NotNilIterator<T: IteratorProtocol, U>: IteratorProtocol where T.Element == U? {
typealias Element = U
var iterator: T
init(_ source: T) {
iterator = source
}
func next() -> Element? {
// I feel this is clearer what is going on
while true {
switch iterator.next() {
case .some(.none):
continue
case .none:
return nil
case .some(.some(let element)):
return element
}
}
}
}
class NotNilSequence<T: Sequence, U> : Sequence where T.Element == U?
{
let sequence: T
init(_ source : T)
{
sequence = source
}
public func makeIterator() -> NotNilIterator<T.Iterator, U>
{
.init(sequence.makeIterator())
}
}
whereNotNil would then be declared like this:
func whereNotNil<T>() -> NotNilSequence<Self, T> where Self.Element == T?
{
return .init(self)
}
Note the use of self types. The first parameter is the type of the underlying sequence, the second is the non-optional type.
Note that this sort of "lazily computed sequence" is already built into Swift. To lazily filter out the nils, do:
let array = [1, 2, 3, nil, 4]
let arrayWithoutNil = array.lazy.compactMap { $0 }
The downside is that the type names are quite long. arrayWithoutNil is of type
LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[Int?]>.Elements, Int?>>, Int>
But you can indeed get non-optional Ints out of it, so it does work.
The way swift generics work can sometimes be very confusing (but has it's advantages). Instead of declaring that a variable is of a generic protocol (resp. a protocol with associated types), you instead declare another generic type which itself conforms to your protocol. Here's your iterator as an example (I have taken the liberty to clean up the code a bit):
public class Not_null_iterator<T, T_iterator> : IteratorProtocol where
T_iterator: IteratorProtocol,
T_iterator.Element == Optional<T>
{
private var source: T_iterator
init(_ source: T_iterator) {
self.source = source
}
public func next() -> T? {
while let next_value = source.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
return nil
}
}
The non-null sequence works analogous:
public class Not_null_sequence<T, Source>: Sequence where
Source: Sequence,
Source.Element == Optional<T>
{
private var source: Source
init(_ source: Source) {
self.source = source
}
public func makeIterator() -> Not_null_iterator<T, Source.Iterator> {
Not_null_iterator(self.source.makeIterator())
}
}
Using this some IteratorProtocol is just a nice way to let the compiler figure out the type. It is equivalent to saying Not_null_iterator<T, Source.Iterator>
As a (potentially) interesting side-note, to clean up the generic mess even more, you can nest the iterator class inside the Not_null_sequence:
public class Not_null_sequence<T, Source>: Sequence where
Source: Sequence,
Source.Element == Optional<T>
{
private var source: Source
init(_ source: Source) {
self.source = source
}
public func makeIterator() -> Iterator{
Iterator(self.source.makeIterator())
}
public class Iterator: IteratorProtocol {
private var source: Source.Iterator
init(_ source: Source.Iterator) {
self.source = source
}
public func next() -> T? {
while let next_value = source.next()
{
if let not_null_value = next_value
{
return not_null_value
}
}
return nil
}
}
}

Optional extension for any types

I want to write Optional extension for any types.
My code for integer:
extension Optional where Wrapped == Int {
func ifNil<T>(default: T) -> T {
if self != nil {
return self as! T
}
return default
}
}
var tempInt: Int?
tempInt.ifNil(default: 2) // returns 2
tempInt = 5
tempInt.ifNil(default: 2) // returns 5
It works but it is Optional(Int) extension (Optional where Wrapped == Int), I want to use this extension for any types like Date, String, Double etc.
What are your suggestions?
The answer to your basic question is to just remove the where clause:
extension Optional {
// ... the rest is the same
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
Now it applies to all Optionals.
But this code is quite broken. It crashes if T is not the same as Wrapped. So you would really mean a non-generic function that works on Wrapped:
extension Optional {
func isNil(value: Wrapped) -> Wrapped {
if self != nil {
return self! // `as!` is unnecessary
}
return value
}
}
But this is just an elaborate way of saying ?? (as matt points out)
extension Optional {
func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Except that ?? is much more powerful. It includes an autoclosure that avoids evaluating the default value unless it's actually used, and which can throw. It's also much more idiomatic Swift in most cases. You can find the source on github.
public func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
But I can imagine cases where you might a method-based solution (they're weird, but maybe there are such cases). You can get that by just rewriting it as a method:
extension Optional {
public func value(or defaultValue: #autoclosure () throws -> Wrapped) rethrows -> Wrapped {
switch self {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
tempInt.value(or: 2)
Optional is already a generic. It already takes any type as its parameterized type. Its parameterized already has a name: Wrapped. Just say Wrapped instead of T. Your T is Wrapped.
extension Optional {
func isNil<Wrapped>(value: Wrapped) -> Wrapped {
if self != nil {
return self as! Wrapped
}
return value
}
}
If you really prefer T for some reason, use a type alias. It's only a name:
extension Optional {
typealias T = Wrapped
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
But in any case your extension is completely unnecessary because this is what the nil-coalescing operator ?? already does.
var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5

Using Swift generics in a RxSwift getter function - various problems

Here's the function:
func registerFor<Element>(relayId id: String) -> Driver<Element>? {
guard let relay = relays[id] as? BehaviorRelay<Element> else { return nil }
return relay.asObservable()
.distinctUntilChanged { a, b in
return a != b
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: Element())
}
The distinctUntilChanged line throws the following error:
Contextual closure type '(Element) throws -> _' expects 1 argument,
but 2 were used in closure body
The asDriver line throws the following error (of course):
Non-nominal type 'Element' does not support explicit initialization
Context: I have a class that ideally has a collection of BehaviorRelays of various types (Strings, Ints, etc). Element stands in generically for these types, but that creates two problems:
distinctUntilChanged insists of having a closure (eg: if this method returned Driver<String> it would be content simply to use distinctUntilChanged() but the generic Element makes it complain about missing a closure);
onErrorJustReturn requires a concrete value, but Element is generic.
The following "workaround" might work but I suspect there are better solutions
protocol Inii {
init()
}
func registerFor(relayId id: String, def: Inii.Type) -> Driver<Inii>? {
return relays[id]?.asObservable()
.distinctUntilChanged { _, _ in
return true
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: def.init())
}
Although I'm still unsure what to put in the distinctUntilChanged closure.
Appendix A
I believe that the following is what is required if one is implementing the distinctUntilChanged closure for a non-generic type:
.distinctUntilChanged { previousValue, currentValue in
return previousValue == currentValue
}
However, when used with the generic Element the following error is still thrown:
Contextual closure type '(Inii) throws -> _' expects 1 argument,
but 2 were used in closure body
Appendix B
Here's another alternative with a slightly different problem:
protocol Inii {
init()
}
var relay = BehaviorRelay<String>(value: "")
func registerFor<Element>(def: Element.Type) -> Driver<Element> where Element: Inii {
return relay.asObservable()
.distinctUntilChanged { previousValue, currentValue in
return previousValue == currentValue
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: def.init())
}
Error in this case being:
Member 'next' in 'Event<_>' produces result of type 'Event<Element>',
but context expects 'Event<_>'
at the observer.on line
You can use distinctUntilChanged() without a closure as long as Element conforms to Equatable:
protocol EmptyInit {
init()
}
func registerFor<Element>(relayId id: String) -> Driver<Element>? where Element: Equatable, Element: EmptyInit {
guard let relay = relays[id] as? BehaviorRelay<Element> else { return nil }
return relay.asObservable()
.distinctUntilChanged()
.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: Element())
}

conforming to Sequence and IteratorProtocol in Swift

I am trying to write my own version of IndexingIterator to increase my understanding of Sequence. I haven't assign any type to associatetype Iterator in my struct. However, the complier doesn't complain about that and I get a default implementation of makeIterator.
Following are my codes:
struct __IndexingIterator<Elements: IndexableBase>: Sequence, IteratorProtocol {
mutating func next() -> Elements._Element? {
return nil
}
}
let iterator = __IndexingIterator<[String]>()
// this works and returns an instance of __IndexingIterator<Array<String>>. why?
iterator.makeIterator()
I think there must be some extensions on Sequence which add the default implementation. Thus, I searched it in Sequence.swift and only found this.
extension Sequence where Self.Iterator == Self, Self : IteratorProtocol {
/// Returns an iterator over the elements of this sequence.
public func makeIterator() -> Self {
return self
}
}
I thought it would be like this:
extension Sequence where Self: IteratorProtocol {
typealias Iterator = Self
...
}
Did I miss something or I misunderstood the extension?
It looks like Alexander's answer is correct. Here's a boiled down version, without using Sequence:
protocol MySequence {
associatedtype Iterator: IteratorProtocol
func maakeIterator() -> Iterator
}
extension MySequence where Self.Iterator == Self, Self : IteratorProtocol {
/// Returns an iterator over the elements of this sequence.
func maakeIterator() -> Self {
return self
}
}
struct __IndexingIterator<Element>: MySequence, IteratorProtocol {
mutating func next() -> Element? {
return nil
}
}
let iterator = __IndexingIterator<[String]>()
iterator.maakeIterator()
You can write your own Iterator which confrom to IteratorProtocol first, then write what you need confrom to Sequence.
Make sure that you have to implement requried func.
struct IteratorTest : IteratorProtocol {
typealias Element = Int
var count : Int
init(count :Int) {
self.count = count
}
mutating func next() -> Int? {
if count == 0 {
return nil
}else {
defer {
count -= 1
}
return count;
}
}
}
struct CountDown : Sequence {
typealias Iterator = IteratorTest
func makeIterator() -> IteratorTest {
return IteratorTest.init(count: 10)
}
}
The type alias isn't necessary, because the Element associated type is inferred from your implementation of next().
Here's a simple example:
protocol ResourceProvider {
associatedtype Resoruce
func provide() -> Resoruce;
}
struct StringProvider {
func provide() -> String { // "Resource" inferred to be "String"
return "A string"
}
}

How can I write a function that will unwrap a generic property in swift assuming it is an optional type?

So far I have only been able to achieve this using a global function. I am not sure if it is possible but I was hoping to write an extension to a generic class that would hopefully achieve the same thing.
Below is the working global function it is using SignalProducer class from ReactiveCocoa but the principle should be the same for any generic class.
func ignoreNilValues <Value,Error> (producer: SignalProducer<Value?,Error>) -> SignalProducer<Value, Error> {
return producer.filter { return $0 != nil }.map { $0! }
}
Update:
I have made progress but have still fallen short of a complete solution
Given any class with some generic property
class GenericClass<SomeType> {
var someProperty: [SomeType] = []
}
How can I write an extension that will filter any optional values and return the value using the Wrapped type?
The following will filter any nil values but still return it as the Optional type.
protocol AnOptional {
var isNil: Bool {get}
}
extension Optional : AnOptional {
var isNil: Bool {
get {
guard let hasValue = self.map({ (value: Wrapped) -> Bool in
return true
}) else {
return true
}
return !hasValue
}
}
}
extension GenericClass where SomeType : AnOptional {
func filterNilValuesOfSomeProperty() -> [SomeType] {
return someProperty.filter({ (anOptional: AnOptional) -> Bool in
return !anOptional.isNil
})
}
}
As can be seen
let aClass = GenericClass<Int?>()
aClass.someProperty = [3,5,6,nil,4,3,6, nil]
let x = aClass.someProperty
//x = [Some(3),Some(5),Some(6),nil,Some(4),Some(3),Some(6), nil]
let y = aClass.filterNilValuesOfSomeProperty()
//y = [Some(3),Some(5),Some(6),Some(4),Some(3),Some(6)]
Is it possible to write a class extension that would return the wrapped type? In the example above it would be [Int] instead of [Int?].
I rewrote the global function solution for this example.
func ignoreNilValues <Value> (aClass: GenericClass<Value?>) -> GenericClass<Value> {
let aNewClass = GenericClass<Value>()
aNewClass.someProperty = aClass.someProperty.filter({ (v: Value?) -> Bool in
v != nil
}).map { (oldValue: Value?) -> Value in
return oldValue!
}
return aNewClass
}
let z = ignoreNilValues(aClass).someProperty
//z = [3, 5, 6, 4, 3, 6]
The "trick" is to define a protocol to which all optionals conform
(this is from Creating an extension to filter nils from an Array in Swift
with a minor simplification; the idea goes back to this Apple Forum Thread):
protocol OptionalType {
typealias Wrapped
func intoOptional() -> Wrapped?
}
extension Optional : OptionalType {
func intoOptional() -> Wrapped? {
return self
}
}
You can use that in your case as:
class GenericClass<SomeType> {
var someProperty: [SomeType] = []
}
extension GenericClass where SomeType : OptionalType {
func filterNilValuesOfSomeProperty() -> [SomeType.Wrapped] {
return someProperty.flatMap { $0.intoOptional() }
}
}
which uses the flatMap() method from SequenceType:
extension SequenceType {
/// Return an `Array` containing the non-nil results of mapping
/// `transform` over `self`.
///
/// - Complexity: O(*M* + *N*), where *M* is the length of `self`
/// and *N* is the length of the result.
#warn_unused_result
public func flatMap<T>(#noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}
Example:
let aClass = GenericClass<Int?>()
aClass.someProperty = [3,5,6,nil,4,3,6, nil]
let x = aClass.someProperty
print(x) // [Optional(3), Optional(5), Optional(6), nil, Optional(4), Optional(3), Optional(6), nil]
let y = aClass.filterNilValuesOfSomeProperty()
print(y) // [3, 5, 6, 4, 3, 6]
In Swift 3 and later the protocol has to be defined as
protocol OptionalType {
associatedtype Wrapped
func intoOptional() -> Wrapped?
}
I have this solution using in my app, create a protocol, and added an extension to Optional.
protocol OptionalUnwrap {
associatedtype Wrapped
func unwrap(default defaultValue: #autoclosure () -> Wrapped) -> Wrapped
}
extension Optional: OptionalUnwrap {
func unwrap(default defaultValue: #autoclosure () -> Wrapped) -> Wrapped {
if let value = self {
return value
}
return defaultValue()
}
}
You can use it like this, you have to provide a default value, so if optional is nil it will return the default value. It works with all types.
struct StructName {
var name: String
var age: Int
}
var structName3: StructName?
let unwrapped = structName3.unwrap(default: StructName(name: "", age: 2345))
print(unwrapped.age)
var version: Int?
version.unwrap(default: 5)
var subject: String? = "iOS"
subject.unwrap(default: "")