Pages

Saturday, July 18, 2020

A simple Example of SignalProducer ReactiveSwift

Recently I started to work on a project which is totally in Swift and Signal. As I mostly worked on Objective-C and C++ based projects, from Objective C background I really don’t like Swift that much, and honestly this ReactiveSwift, I hope it will change after some time. And for me, SignalProducer or Signals is very complex. When I searched for tutorials with real-life examples, what I found is that, whether they are too old or does not meet my requirements, also I didn’t get much time to study these things. 

If you want to learn theory or want to clear your concept about ReactiveSwift or Signals this article is not for you. Here I will share the examples I came up with to help me to implement the same scenario in my project. 

If you are already experienced in these please feel free to share your comments so that I and other people get to learn something from you :)


Let’s get to point

Let's say we have a Downloader class which only perform the download, and which have no idea about ReactiveSwift, we want to integrate this class with our app using ReactiveSwift, also we have DownloaderDelegate. Let's check them first.

protocol DownloaderDelegate {
func downloadFinished()
func downloadCanceled()
}
class Downloader {
var progress: Int
var shouldStop: Bool
var delegate: DownloaderDelegate?
init(delegate: DownloaderDelegate) {
progress = 0
shouldStop = false
self.delegate = delegate
}
func startDownloading() {
DispatchQueue.global().async {
//lets say we are donwloading here,
for index in 0..<10 {
sleep(1)
log("[Downloader] Progress \(index*10)%")
if self.shouldStop {
self.delegate?.downloadCanceled()
return
}
}
self.delegate?.downloadFinished()
}
}
func stopDownloading() {
shouldStop = true
}
}

Now Let's say we are going to create a DownloadManager class which will use this class and implement SignalProducer so that our application can access this just like other classes using ReactiveSwift.

class DownloadManager {
var observer: Signal<Int, Error>.Observer? = nil
var lifetime: Lifetime? = nil
var downloader: Downloader?
func start() -> SignalProducer<Int, Swift.Error> {
let signalProducer: SignalProducer<Int, Swift.Error> = SignalProducer { (observer, lifetime) in
//this block won't execute untill someone start this signal
log("[DownloadManager] Download Starting")
self.downloader = Downloader(delegate: self)
self.downloader?.startDownloading()
self.observer = observer
self.lifetime = lifetime
}
return signalProducer
}
func stop() {
log("[DownloadManager] IN")
self.downloader?.stopDownloading()
log("[DownloadManager] OUT")
}
}


Here is the Tester class where we will use DownloadManager class

class DownloadTester {
func testDownloader() {
let manager = DownloadManager()

manager.start().startWithResult { (result) in
switch result {
case .success(let progress) :
print(progress)
print("[DownloadTester] Download Complete: \(progress)")
case .failure(let err):
print(err)
}
}
//to test stop downloading
DispatchQueue.global().async {
sleep(3)
manager.stop()
}
}
}


If you want to see the whole class please check here

I wanted to use github gist but no way I could embedded it here :( 

If you know how to do that please share.

https://github.com/razibdeb/ReactiveSwiftSamples/blob/master/DownloaderSample.swift

No comments: