Dealing With Resources in RxSwift

Daniel Tartaglia
3 min readMay 28, 2022

The Observable.using(_:observableFactory:) function is designed to tie the lifetime of a resource to the subscription of an Observable. In order to use it, you provide a closure that creates the resource and another closure that returns the Observable that will be tied to the resource. Then anytime the Observable returned by using is subscribed to, the operator will call both closures in order to create the resource and return an Observable, bound to the one from the second function. When the Observable is disposed, the using operator will call dispose() on the resource and then deallocate it.

Making a Resource

All this is pretty abstract though. What does it look like in practice? I recently was working on a screen that played audio files. One way to do that is to use the AVAudioPlayer class; a resource.

final class AudioSession: Disposable {
let audioPlayer: AVAudioPlayer
init(url: URL) throws {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
}
func dispose() {
audioPlayer.stop()
}
}

When the above resource is created, it will make the audio player and start playing. When the resource is disposed, it will stop the audio player. Now we can use it in the using operator like so:

let session = Observable.using({
try AudioSession(url: url)
},
observableFactory: { audioSession in
Observable<Never>.never()
})

When you subscribe to session it will create the AudioSession resource, and thus start playing the sound file. When you dispose that subscription, it will stop playing the sound file and delete the audio player object.

Getting Information Out of a Resource

As written, the above observable doesn’t emit anything. Its only reason for existence is to create and dispose the resource, but it can emit information about the observable. For example, you could have it emit the current play time:

return Observable<Int>.interval(
.milliseconds(100),
scheduler: MainScheduler.instance
)
.flatMap { _ in
Observable.just(audioSession.audioPlayer.currentTime)
}

Putting the above code into the observableFactory closure will let you know something about what’s going on with the resource. More information can be added as well.

Sending Information Into a Resource

You can also send information into the resource using an Observable. For example toggling from the play/pause state.

If you give your resource a dispose bag, you can add yet more to that closure:

togglePlay // an Observable<Void>
.subscribe(onNext: audioSession.audioPlayer.toggle)
.disposed(by: audioSession.disposeBag)

(The toggle() function is an extension I wrote to toggle between play and pause.)

Other Uses for using

So any time you need to create and release resources in your Rx code, the using operator is there to help you. However, it can be used for even more. Anytime you want to call some code during subscription and call other code during dispose, the using operator is your friend.

One of the most interesting ideas I’ve had for the operator is when I treated a UIViewController as a resource. Resource creation makes the view controller and presents it, and disposing the resource dismisses the view controller.

Examples

I have created a generic Resource type that makes it easier to wrap resources along with several examples. If you make resources that you would like to share, by all means send a pull request and I’d love to add it.

Check out my RxResource repository for more.

--

--

Daniel Tartaglia

I started programming as a hobby in the late ’70s and professionally in the late ’90s. I’ve been writing iOS apps since 2010 and using RxSwift since 2015.