Observable implementation
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
I have implemented a simple Observable class. I think that there is still room for improvement. Especially the fact that I have separate array to observe results
and values
what if I want to observe errors for example, I think that this solution can be improved to be scalable. Also I'm not sure who is responsible for the threading the class implementation or the caller.
the desired result is to have an interface that allows:
1) Observable declaration:
private let isLoadingObservable = Observable<Bool>(false)
2) Update value:
self.isLoadingObservable.value = true
3) Observe values changes:
override func viewDidLoad()
super.viewDidLoad()
isLoadingObservable.observeValues(on: self) isLoading in
print(isLoading)
Also in case where failure is possible (network call for example) we can user Result
:
1) Observable declaration:
private let dataObservable = Observable<[User]>()
2) Update value:
dataObservable.result = Result.failure(URLError.badURL)
3) Observe result changes:
dataObservable.observeResults(on: self) result in
switch result
case .success(let value):
print(value)
case .failure(let error):
print(error)
where we have
struct User
let name: String
enum ServerError: Error
case invalidDataError
The implementation:
import Foundation
public enum Result<Value>
case success(Value)
case failure(Error)
var value: Value?
switch self
case .success(let value):
return value
case .failure:
return nil
class ResultObserver<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
weak var observer: AnyObject?
let block: ResultObserverBlock
init(observer: AnyObject, block: @escaping ResultObserverBlock)
self.observer = observer
self.block = block
class ValueObserver<Value>
typealias ValueObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ValueObserverBlock
init(observer: AnyObject, block: @escaping ValueObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
//MARK: - Private properties
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
//MARK: - Public properties
public var result : Result<Value>
didSet
self.notifyObservers()
public var value: Value?
get
return self.result.value
set
if let value = newValue
self.result = Result.success(value)
//MARK: - Struct lifecycle
public init(_ result: Result<Value>)
self.result = result
public convenience init(_ value: Value)
self.init(Result.success(value))
public convenience init(_ error: Error)
self.init(Result.failure(error))
//MARK: - Observation
func observeResults(on observer: AnyObject, observerBlock: @escaping ResultObserverBlock)
self.resultObservers.append(ResultObserver(observer: observer, block: observerBlock))
observerBlock(result)
func observeValues(on observer: AnyObject, observerBlock: @escaping ValueObserverBlock)
self.valueObservers.append(ValueObserver(observer: observer, block: observerBlock))
if let value = value
observerBlock(value)
func remove(observer: AnyObject)
self.resultObservers = self.resultObservers.filter($0.observer !== observer)
self.valueObservers = self.valueObservers.filter($0.observer !== observer)
//MARK: - Helpers
private func notifyObservers()
for observer in self.valueObservers
if let value = value
observer.block(value)
for observer in self.resultObservers
observer.block(result)
swift ios observer-pattern reactive-programming
add a comment |Â
up vote
1
down vote
favorite
I have implemented a simple Observable class. I think that there is still room for improvement. Especially the fact that I have separate array to observe results
and values
what if I want to observe errors for example, I think that this solution can be improved to be scalable. Also I'm not sure who is responsible for the threading the class implementation or the caller.
the desired result is to have an interface that allows:
1) Observable declaration:
private let isLoadingObservable = Observable<Bool>(false)
2) Update value:
self.isLoadingObservable.value = true
3) Observe values changes:
override func viewDidLoad()
super.viewDidLoad()
isLoadingObservable.observeValues(on: self) isLoading in
print(isLoading)
Also in case where failure is possible (network call for example) we can user Result
:
1) Observable declaration:
private let dataObservable = Observable<[User]>()
2) Update value:
dataObservable.result = Result.failure(URLError.badURL)
3) Observe result changes:
dataObservable.observeResults(on: self) result in
switch result
case .success(let value):
print(value)
case .failure(let error):
print(error)
where we have
struct User
let name: String
enum ServerError: Error
case invalidDataError
The implementation:
import Foundation
public enum Result<Value>
case success(Value)
case failure(Error)
var value: Value?
switch self
case .success(let value):
return value
case .failure:
return nil
class ResultObserver<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
weak var observer: AnyObject?
let block: ResultObserverBlock
init(observer: AnyObject, block: @escaping ResultObserverBlock)
self.observer = observer
self.block = block
class ValueObserver<Value>
typealias ValueObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ValueObserverBlock
init(observer: AnyObject, block: @escaping ValueObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
//MARK: - Private properties
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
//MARK: - Public properties
public var result : Result<Value>
didSet
self.notifyObservers()
public var value: Value?
get
return self.result.value
set
if let value = newValue
self.result = Result.success(value)
//MARK: - Struct lifecycle
public init(_ result: Result<Value>)
self.result = result
public convenience init(_ value: Value)
self.init(Result.success(value))
public convenience init(_ error: Error)
self.init(Result.failure(error))
//MARK: - Observation
func observeResults(on observer: AnyObject, observerBlock: @escaping ResultObserverBlock)
self.resultObservers.append(ResultObserver(observer: observer, block: observerBlock))
observerBlock(result)
func observeValues(on observer: AnyObject, observerBlock: @escaping ValueObserverBlock)
self.valueObservers.append(ValueObserver(observer: observer, block: observerBlock))
if let value = value
observerBlock(value)
func remove(observer: AnyObject)
self.resultObservers = self.resultObservers.filter($0.observer !== observer)
self.valueObservers = self.valueObservers.filter($0.observer !== observer)
//MARK: - Helpers
private func notifyObservers()
for observer in self.valueObservers
if let value = value
observer.block(value)
for observer in self.resultObservers
observer.block(result)
swift ios observer-pattern reactive-programming
IfResult
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.
â Martin R
Jan 24 at 12:35
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
That does not compile, there are several errors (related toResult<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.
â Martin R
Jan 24 at 12:42
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have implemented a simple Observable class. I think that there is still room for improvement. Especially the fact that I have separate array to observe results
and values
what if I want to observe errors for example, I think that this solution can be improved to be scalable. Also I'm not sure who is responsible for the threading the class implementation or the caller.
the desired result is to have an interface that allows:
1) Observable declaration:
private let isLoadingObservable = Observable<Bool>(false)
2) Update value:
self.isLoadingObservable.value = true
3) Observe values changes:
override func viewDidLoad()
super.viewDidLoad()
isLoadingObservable.observeValues(on: self) isLoading in
print(isLoading)
Also in case where failure is possible (network call for example) we can user Result
:
1) Observable declaration:
private let dataObservable = Observable<[User]>()
2) Update value:
dataObservable.result = Result.failure(URLError.badURL)
3) Observe result changes:
dataObservable.observeResults(on: self) result in
switch result
case .success(let value):
print(value)
case .failure(let error):
print(error)
where we have
struct User
let name: String
enum ServerError: Error
case invalidDataError
The implementation:
import Foundation
public enum Result<Value>
case success(Value)
case failure(Error)
var value: Value?
switch self
case .success(let value):
return value
case .failure:
return nil
class ResultObserver<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
weak var observer: AnyObject?
let block: ResultObserverBlock
init(observer: AnyObject, block: @escaping ResultObserverBlock)
self.observer = observer
self.block = block
class ValueObserver<Value>
typealias ValueObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ValueObserverBlock
init(observer: AnyObject, block: @escaping ValueObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
//MARK: - Private properties
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
//MARK: - Public properties
public var result : Result<Value>
didSet
self.notifyObservers()
public var value: Value?
get
return self.result.value
set
if let value = newValue
self.result = Result.success(value)
//MARK: - Struct lifecycle
public init(_ result: Result<Value>)
self.result = result
public convenience init(_ value: Value)
self.init(Result.success(value))
public convenience init(_ error: Error)
self.init(Result.failure(error))
//MARK: - Observation
func observeResults(on observer: AnyObject, observerBlock: @escaping ResultObserverBlock)
self.resultObservers.append(ResultObserver(observer: observer, block: observerBlock))
observerBlock(result)
func observeValues(on observer: AnyObject, observerBlock: @escaping ValueObserverBlock)
self.valueObservers.append(ValueObserver(observer: observer, block: observerBlock))
if let value = value
observerBlock(value)
func remove(observer: AnyObject)
self.resultObservers = self.resultObservers.filter($0.observer !== observer)
self.valueObservers = self.valueObservers.filter($0.observer !== observer)
//MARK: - Helpers
private func notifyObservers()
for observer in self.valueObservers
if let value = value
observer.block(value)
for observer in self.resultObservers
observer.block(result)
swift ios observer-pattern reactive-programming
I have implemented a simple Observable class. I think that there is still room for improvement. Especially the fact that I have separate array to observe results
and values
what if I want to observe errors for example, I think that this solution can be improved to be scalable. Also I'm not sure who is responsible for the threading the class implementation or the caller.
the desired result is to have an interface that allows:
1) Observable declaration:
private let isLoadingObservable = Observable<Bool>(false)
2) Update value:
self.isLoadingObservable.value = true
3) Observe values changes:
override func viewDidLoad()
super.viewDidLoad()
isLoadingObservable.observeValues(on: self) isLoading in
print(isLoading)
Also in case where failure is possible (network call for example) we can user Result
:
1) Observable declaration:
private let dataObservable = Observable<[User]>()
2) Update value:
dataObservable.result = Result.failure(URLError.badURL)
3) Observe result changes:
dataObservable.observeResults(on: self) result in
switch result
case .success(let value):
print(value)
case .failure(let error):
print(error)
where we have
struct User
let name: String
enum ServerError: Error
case invalidDataError
The implementation:
import Foundation
public enum Result<Value>
case success(Value)
case failure(Error)
var value: Value?
switch self
case .success(let value):
return value
case .failure:
return nil
class ResultObserver<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
weak var observer: AnyObject?
let block: ResultObserverBlock
init(observer: AnyObject, block: @escaping ResultObserverBlock)
self.observer = observer
self.block = block
class ValueObserver<Value>
typealias ValueObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ValueObserverBlock
init(observer: AnyObject, block: @escaping ValueObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
//MARK: - Private properties
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
//MARK: - Public properties
public var result : Result<Value>
didSet
self.notifyObservers()
public var value: Value?
get
return self.result.value
set
if let value = newValue
self.result = Result.success(value)
//MARK: - Struct lifecycle
public init(_ result: Result<Value>)
self.result = result
public convenience init(_ value: Value)
self.init(Result.success(value))
public convenience init(_ error: Error)
self.init(Result.failure(error))
//MARK: - Observation
func observeResults(on observer: AnyObject, observerBlock: @escaping ResultObserverBlock)
self.resultObservers.append(ResultObserver(observer: observer, block: observerBlock))
observerBlock(result)
func observeValues(on observer: AnyObject, observerBlock: @escaping ValueObserverBlock)
self.valueObservers.append(ValueObserver(observer: observer, block: observerBlock))
if let value = value
observerBlock(value)
func remove(observer: AnyObject)
self.resultObservers = self.resultObservers.filter($0.observer !== observer)
self.valueObservers = self.valueObservers.filter($0.observer !== observer)
//MARK: - Helpers
private func notifyObservers()
for observer in self.valueObservers
if let value = value
observer.block(value)
for observer in self.resultObservers
observer.block(result)
swift ios observer-pattern reactive-programming
edited Jan 26 at 12:02
asked Jan 24 at 12:07
iOSGeek
1737
1737
IfResult
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.
â Martin R
Jan 24 at 12:35
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
That does not compile, there are several errors (related toResult<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.
â Martin R
Jan 24 at 12:42
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13
add a comment |Â
IfResult
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.
â Martin R
Jan 24 at 12:35
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
That does not compile, there are several errors (related toResult<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.
â Martin R
Jan 24 at 12:42
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13
If
Result
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.â Martin R
Jan 24 at 12:35
If
Result
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.â Martin R
Jan 24 at 12:35
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
That does not compile, there are several errors (related to
Result<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.â Martin R
Jan 24 at 12:42
That does not compile, there are several errors (related to
Result<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.â Martin R
Jan 24 at 12:42
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
There is quite a lot of "almost similar" code due to the fact that you
treat "value observers" and "result observers" separately:
Two classes
class ResultObserver<Value>
class ValueObserver<Value>
with corresponding type aliases:
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
and instance variables
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
three init methods, two observeResults()
methods, etc.
This would be greatly simplified by just observing a generic
type Value
, which in particular can be a Result<>
:
class Observer<Value>
typealias ObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ObserverBlock
init(observer: AnyObject, block: @escaping ObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
//MARK: - Private properties
private var observers = [Observer<Value>]()
//MARK: - Public properties
public var value : Value
didSet
self.notifyObservers()
//MARK: - Struct lifecycle
public init(_ value: Value)
self.value = value
//MARK: - Observation
func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock)
self.observers.append(Observer(observer: observer, block: observerBlock))
observerBlock(value)
func remove(observer: AnyObject)
self.observers = self.observers.filter( $0.observer !== observer )
//MARK: - Helpers
private func notifyObservers()
for observer in self.observers
observer.block(value)
Note also the use of Observer<Value>.ObserverBlock
in order to
avoid defining the same closure type twice.
Now you can observe a simple (boolean) value:
private let isLoadingObservable = Observable(false)
// ...
isLoadingObservable.observe(on: self) isLoading in
print("observed:", isLoading)
or a result:
private let dataObservable = Observable(Result<[User]>.success())
// ...
dataObservable.observe(on: self) result in
switch result
case .success(let value):
print("Value:", value)
case .failure(let error):
print("Error:", error)
Another possible improvement could be to check in func notifyObservers()
if the observing object still is alive, and
remove it from the list otherwise.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
There is quite a lot of "almost similar" code due to the fact that you
treat "value observers" and "result observers" separately:
Two classes
class ResultObserver<Value>
class ValueObserver<Value>
with corresponding type aliases:
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
and instance variables
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
three init methods, two observeResults()
methods, etc.
This would be greatly simplified by just observing a generic
type Value
, which in particular can be a Result<>
:
class Observer<Value>
typealias ObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ObserverBlock
init(observer: AnyObject, block: @escaping ObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
//MARK: - Private properties
private var observers = [Observer<Value>]()
//MARK: - Public properties
public var value : Value
didSet
self.notifyObservers()
//MARK: - Struct lifecycle
public init(_ value: Value)
self.value = value
//MARK: - Observation
func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock)
self.observers.append(Observer(observer: observer, block: observerBlock))
observerBlock(value)
func remove(observer: AnyObject)
self.observers = self.observers.filter( $0.observer !== observer )
//MARK: - Helpers
private func notifyObservers()
for observer in self.observers
observer.block(value)
Note also the use of Observer<Value>.ObserverBlock
in order to
avoid defining the same closure type twice.
Now you can observe a simple (boolean) value:
private let isLoadingObservable = Observable(false)
// ...
isLoadingObservable.observe(on: self) isLoading in
print("observed:", isLoading)
or a result:
private let dataObservable = Observable(Result<[User]>.success())
// ...
dataObservable.observe(on: self) result in
switch result
case .success(let value):
print("Value:", value)
case .failure(let error):
print("Error:", error)
Another possible improvement could be to check in func notifyObservers()
if the observing object still is alive, and
remove it from the list otherwise.
add a comment |Â
up vote
1
down vote
There is quite a lot of "almost similar" code due to the fact that you
treat "value observers" and "result observers" separately:
Two classes
class ResultObserver<Value>
class ValueObserver<Value>
with corresponding type aliases:
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
and instance variables
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
three init methods, two observeResults()
methods, etc.
This would be greatly simplified by just observing a generic
type Value
, which in particular can be a Result<>
:
class Observer<Value>
typealias ObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ObserverBlock
init(observer: AnyObject, block: @escaping ObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
//MARK: - Private properties
private var observers = [Observer<Value>]()
//MARK: - Public properties
public var value : Value
didSet
self.notifyObservers()
//MARK: - Struct lifecycle
public init(_ value: Value)
self.value = value
//MARK: - Observation
func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock)
self.observers.append(Observer(observer: observer, block: observerBlock))
observerBlock(value)
func remove(observer: AnyObject)
self.observers = self.observers.filter( $0.observer !== observer )
//MARK: - Helpers
private func notifyObservers()
for observer in self.observers
observer.block(value)
Note also the use of Observer<Value>.ObserverBlock
in order to
avoid defining the same closure type twice.
Now you can observe a simple (boolean) value:
private let isLoadingObservable = Observable(false)
// ...
isLoadingObservable.observe(on: self) isLoading in
print("observed:", isLoading)
or a result:
private let dataObservable = Observable(Result<[User]>.success())
// ...
dataObservable.observe(on: self) result in
switch result
case .success(let value):
print("Value:", value)
case .failure(let error):
print("Error:", error)
Another possible improvement could be to check in func notifyObservers()
if the observing object still is alive, and
remove it from the list otherwise.
add a comment |Â
up vote
1
down vote
up vote
1
down vote
There is quite a lot of "almost similar" code due to the fact that you
treat "value observers" and "result observers" separately:
Two classes
class ResultObserver<Value>
class ValueObserver<Value>
with corresponding type aliases:
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
and instance variables
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
three init methods, two observeResults()
methods, etc.
This would be greatly simplified by just observing a generic
type Value
, which in particular can be a Result<>
:
class Observer<Value>
typealias ObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ObserverBlock
init(observer: AnyObject, block: @escaping ObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
//MARK: - Private properties
private var observers = [Observer<Value>]()
//MARK: - Public properties
public var value : Value
didSet
self.notifyObservers()
//MARK: - Struct lifecycle
public init(_ value: Value)
self.value = value
//MARK: - Observation
func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock)
self.observers.append(Observer(observer: observer, block: observerBlock))
observerBlock(value)
func remove(observer: AnyObject)
self.observers = self.observers.filter( $0.observer !== observer )
//MARK: - Helpers
private func notifyObservers()
for observer in self.observers
observer.block(value)
Note also the use of Observer<Value>.ObserverBlock
in order to
avoid defining the same closure type twice.
Now you can observe a simple (boolean) value:
private let isLoadingObservable = Observable(false)
// ...
isLoadingObservable.observe(on: self) isLoading in
print("observed:", isLoading)
or a result:
private let dataObservable = Observable(Result<[User]>.success())
// ...
dataObservable.observe(on: self) result in
switch result
case .success(let value):
print("Value:", value)
case .failure(let error):
print("Error:", error)
Another possible improvement could be to check in func notifyObservers()
if the observing object still is alive, and
remove it from the list otherwise.
There is quite a lot of "almost similar" code due to the fact that you
treat "value observers" and "result observers" separately:
Two classes
class ResultObserver<Value>
class ValueObserver<Value>
with corresponding type aliases:
typealias ResultObserverBlock = (Result<Value>) -> Void
typealias ValueObserverBlock = (Value) -> Void
and instance variables
private var valueObservers = [ValueObserver<Value>]()
private var resultObservers = [ResultObserver<Value>]()
three init methods, two observeResults()
methods, etc.
This would be greatly simplified by just observing a generic
type Value
, which in particular can be a Result<>
:
class Observer<Value>
typealias ObserverBlock = (Value) -> Void
weak var observer: AnyObject?
let block: ObserverBlock
init(observer: AnyObject, block: @escaping ObserverBlock)
self.observer = observer
self.block = block
public class Observable<Value>
//MARK: - Private properties
private var observers = [Observer<Value>]()
//MARK: - Public properties
public var value : Value
didSet
self.notifyObservers()
//MARK: - Struct lifecycle
public init(_ value: Value)
self.value = value
//MARK: - Observation
func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock)
self.observers.append(Observer(observer: observer, block: observerBlock))
observerBlock(value)
func remove(observer: AnyObject)
self.observers = self.observers.filter( $0.observer !== observer )
//MARK: - Helpers
private func notifyObservers()
for observer in self.observers
observer.block(value)
Note also the use of Observer<Value>.ObserverBlock
in order to
avoid defining the same closure type twice.
Now you can observe a simple (boolean) value:
private let isLoadingObservable = Observable(false)
// ...
isLoadingObservable.observe(on: self) isLoading in
print("observed:", isLoading)
or a result:
private let dataObservable = Observable(Result<[User]>.success())
// ...
dataObservable.observe(on: self) result in
switch result
case .success(let value):
print("Value:", value)
case .failure(let error):
print("Error:", error)
Another possible improvement could be to check in func notifyObservers()
if the observing object still is alive, and
remove it from the list otherwise.
answered Jan 25 at 21:09
Martin R
14.1k12257
14.1k12257
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185872%2fobservable-implementation%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
If
Result
is the only thing that you need from Alamofire then I would suggest to include the definition here directly, to make your code independent of an (otherwise unrelated) framework.â Martin R
Jan 24 at 12:35
@MartinR done, hope that it's easier to be reviewed now
â iOSGeek
Jan 24 at 12:38
That does not compile, there are several errors (related to
Result<Value>
having too few parameters). â Also a (minimal) main program demonstrating the usage might be helpful.â Martin R
Jan 24 at 12:42
@MartinR now it compiles and I have added usage information
â iOSGeek
Jan 24 at 13:13