Ambiguous reference to member 'subscribe' Swift 3 - ios

I am new to Reactive programming, and I'm trying to observe a boolean value from my ViewModel in order to let my ViewController know when to start/stop the app's loader screen.
It's fairly simple and I want to use this method to avoid unnecessary delegates, since my ViewModel holds the business logic and my ViewController handles the UI.
My problem is this compiler error: Ambiguous reference to member 'subscribe'.
It also adds the two possible candidates, as you can see in the image below:
In my ViewModel, I've declared the observable as PublishSubject:
let done = PublishSubject<Bool>()
And I use it while observing another stream:
func subscribe() {
done.onNext(false)
anotherObservable.subscribe(
// other events observed here but not relevant to this matter
onCompleted: {
self.done.onNext(true)
}).addDisposableTo(rx_disposeBag)
}
And, finally, this is how I'm trying to handle it in the ViewController:
self.model.done.subscribe(
.onNext { isDone in
if isDone {
self.removeLoader()
}
}).addDisposableTo(rx_disposeBag)
I believe there is something simple I'm probably missing, so any help is appreciated.

In your second subscribe should be:
self.model.done.subscribe(onNext: { isDone in
if isDone {
self.removeLoader()
}
}).addDisposableTo(rx_disposeBag)

Related

Updating a #State var in SwiftUI from an async method doesn't work

I have the following View:
struct ContentView: View {
#State var data = [SomeClass]()
var body: some View {
List(data, id: \.self) { item in
Text(item.someText)
}
}
func fetchDataSync() {
Task.detached {
await fetchData()
}
}
#MainActor
func fetchData() async {
let data = await SomeService.getAll()
self.data = data
print(data.first?.someProperty)
// > Optional(115)
print(self.data.first?.someProperty)
// > Optional(101)
}
}
now the method fetchDataSync is a delegate that gets called in a sync context whenever there is new data. I've noticed that the views don't change so I've added the printouts. You can see the printed values, which differ. How is this possible? I'm in a MainActor, and I even tried detaching the task. Didn't help. Is this a bug?
It should be mentioned that the objects returned by getAll are created inside that method and not given to any other part of the code. Since they are class objects, the value might be changed from elsewhere, but if so both references should still be the same and not produce different output.
My theory is that for some reason the state just stays unchanged. Am I doing something wrong?
Okay, wow, luckily I ran into the Duplicate keys of type SomeClass were found in a Dictionary crash. That lead me to realize that SwiftUI is doing some fancy diffing stuff, and using the == operator of my class.
The operator wasn't used for actual equality in my code, but rather for just comparing a single field that I used in a NavigationStack. Lesson learned. Don't ever implement == if it doesn't signify true equality or you might run into really odd bugs later.

Generic types on dispatcher job in swift

I'm doing a way to dispatch use case.. It's working very well, but I'm blocked with generic types in swift.
An abstract class responsible to register the observable channels, needs capture the generic handle Output to look if it's a handle success or error, driving the correctly channel handle.
At this moment, my cast generate an exception:
Could not cast value of type
'ios_pokedex_clean.ValueOutput<ios_pokedex_clean.Landing>'
(0x205ea7900) to 'ios_pokedex_clean.Output<Any>' (0x205ea8010).
The Landing is the class expected for view and is knowledge only in the View.
But I don't need to know what is the class in Output when I stay in BaseViewController. Only if notification.object is class Output type.
What I need do to get the behaviors expected?
class Landing : Any{ //it's a way?
...
}
Thinking about... that's works to me was:
#objc func methodOfReceivedNotification(notification: Notification) {
let state = ValueOutput(value: notification.object.self)
if(state.isError()) {
handleThrowable(error: state.error)
} else {
handleSuccess(value: state.value)
}
}
ValueOutput(value: notification.object.self)
avoiding cast.

Memory Leak Kotlin Native library in iOS

I'm building a Kotlin library to use in my iOS app using Kotlin/Native. After I call some methods in the library from Swift, which works, I also want to call methods in Swift from the library. To accomplish this I implemented an interface in the library:
class Outbound {
interface HostInterfaceForTracking {
fun calcFeatureVector(bitmap: Any?): Array<Array<FloatArray>>?
}
var hostInterface: HostInterfaceForTracking? = null
fun registerInterface(hostInterface: HostInterfaceForTracking) {
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
}
}
This is implemented on the Swift side like this:
class HostInterfaceForTracking : OutboundHostInterfaceForTracking {
var t : Outbound? = nil
init() {
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
func calcFeatureVector(bitmap: Any?) -> KotlinArray<KotlinArray<KotlinFloatArray>>? {
do {
var test : Any? = (bitmap as! Bitmap).bitmap
return nil
} catch {
return nil
}
}
}
The TrackingWrapper looks like this:
class TrackingWrapper : NSObject {
static var instance: TrackingWrapper? = nil
var inbound: Inbound? = nil
var worker: Worker
override init() {
self.worker = Worker()
super.init()
initInboundInterface()
}
func initInboundInterface() {
runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
HostInterfaceForTracking()
}
}
func runOnMatchingLibraryThread(block: #escaping() -> Void) {
worker.enqueue {
block()
}
}
}
The function runOnMatchingLibraryThread is needed because every call to the TrackingLibrary needs to be called from the exact same thread, so the Worker class initializes a thread and enqueues every method to that thread.
The Bitmap in this case is simply a wrapper for an UIImage, which I already accessed with the .bitmap call, so I've tried to access the wrapped UIImage and save it in the test variable. The library gets the current camera frame from the Swift side every few frames and sends the current image wrapped as a Bitmap to the method calcFeatureVector depicted here.
Problem: My memory load starts increasing as soon as the app starts until the point it crashes. This is not the case if I don't access the wrapped UIImage (var test : Any? = (bitmap as! Bitmap)). So there is a huge memory leak, just by accessing the wrapped variable on the Swift side. Is there anything I've missed or is there any way to release the memory?
Looks like you have a circular dependency here:
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
You are asking a property inside HostInterfaceForTracking to maintain a strong reference to the same instance of HostInterfaceForTracking. You should be using [weak self] to avoid the circular reference.
EDIT:
Ok after seeing the rest of you code theres a lot to unpack. There is a lot of unnecessary bouncing back and forth between classes, functions and threads.
There is no need to use runOnMatchingLibraryThread to just create an instance of something. You only need to use that for the code processing the image itself (I would assume, I haven't seen anything so far that requires being split off into another thread). Inside TrackingWrapper, you can create a singleton more easily, and matching the swift pattern by simply doing this as the first line:
static let shared = TrackingWrapper()
And everywhere you want to use it, you can just call TrackingWrapper.shared. This is more common and will avoid one of the levels of indirection in the code.
I'm not sure what Worker or Inbound are, but again these can and should be created inside the TrackingWrapper init, rather than branching Inbound's init, to use another thread.
Inside initInboundInterface you are creating an instance of HostInterfaceForTracking() which doesn't get stored anywhere. The only reason HostInterfaceForTracking is continuing to stay in memory after its creation, is because of the internal circular dependency inside it. This is 100% causing some form of a memory issue for you. This should probably also be a property on TrackingWrapper, and again, its Init should not be called inside runOnMatchingLibraryThread.
Having HostInterfaceForTracking's init, also using runOnMatchingLibraryThread is problematic. If we inline all the code whats happening is this:
TrackingWrapper
init() {
self.runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
}
Having all these classes unnecessarily keep coming back to TrackingWrapper is going to cause issues.
Inside HostInterfaceForTracking 's init, no need to be creating Outbound on a separate thread. First line in this class can simply be:
var t : Outbound = OutBound()
Or do it in the init if you prefer. Either way will also remove the issue of needing to unwrap Outbound before using it.
Inside Outbound you are storing 2 references to the hostInterface instance:
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
I would have imagined there should only be 1. If there are now multiple copies of a class that has a circular dependency, which has multiple calls to separate threads. This again will cause issues.
I'm still not sure on the differences between Swift and Kotlin. In Swift when passing self into a function to be stored, the class storing it would mark the property as weak, like so:
weak var hostInterface: ......
Which will avoid any circular dependency from forming. A quick google says this isn't how things work in Kotlin. It might be better to look into the swift side passing in a closure (lambda on kotlin) and the kotlin side executing that. This might avoid the need to store a strong reference. Otherwise you need to be looking into some part of your code setting hostInterface back to null. Again its a bit hard to say only seeing some of the code and not knowing how its working.
In short, it looks like the code is very over complicated, and needs to be simplified, so that all these moving pieces can be tracked easier.

rxswift block life cycle

I have a viewmode class like this :
class ViewMode {
let validateCountResult: Driver<Bool>
init(username: Driver<String>) {
validateCountResult = username
.flatMapLatest { username in
return // validate username
}
}
And I have a subclass of UIViewController as follow :
class ViewController : UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
let viewmode =
ViewMode(textfiled.rx.texttext.orEmpty.asDriver())
viewmode.validateCountResult.drive(onNext:{
// TODO Something
FuncA()
})
}
}
When viewDidload finishes, I believe the viewmode should deinits as well. But I see the binding still exists and FuncA still get called!
Why is it so?
The easiest way to understand binding is to think of the relationship as a connection between two entities:
A producer, which produces the value。
A receiver, which processes the values from the producer.
A receiver cannot return a value. This is a general rule when using bindings of RxSwift.
The fundamental function of binding is bind(to:), and to bind an observable to another entity it's required that the receiver conforms to ObserverType.
You should dispose your Disposable types by creating a DisposeBag.
If you don’t, there is no guarrantee that your viewController even deinits or your disposable types get disposed as well. They create a mutal like together via your ViewMode and all three objects stay in memory.
Take a look at this article to see how to find memory leaks.

In Swift, register "anywhere" to be a delegate of a protocol

I have a complicated view class,
class Snap:UIViewController, UIScrollViewDelegate
{
}
and the end result is the user can, let's say, pick a color...
protocol SnapProtocol:class
{
func colorPicked(i:Int)
}
class Snap:UIViewController, UIScrollViewDelegate
{
someDelegate.colorPicked(blah)
}
So who's going to handle it.
Let's say that you know for sure there is something up the responder chain, even walking through container views, which is a SnapProtocol. If so you can use this lovely code to call it
var r : UIResponder = self
repeat { r = r.nextResponder()! } while !(r is SnapProtocol)
(r as! SnapProtocol).colorPicked(x)
If you prefer, you can use this superlative extension
public extension UIResponder // walk up responder chain
{
public func next<T>() -> T?
{
guard let responder = self.nextResponder()
else { return nil }
return (responder as? T) ?? responder.next()
}
}
courtesy these guys and safely find any SnapProtocol above you,
(next() as SnapProtocol?)?.colorPicked(x)
That's great.
But. What if the object that wants to get the colorPicked is a knight-move away from you, down some complicated side chain, and/or you don't even know which object wants it.
My current solution is this, I have a singleton "game manager" -like class,
public class .. a singleton
{
// anyone who wants a SnapProtocol:
var useSnap:SnapProtocol! = nil
}
Some freaky class, anywhere, wants to eat SnapProtocol ...
class Dinosaur:NSObject, SnapProtocol
{
....
func colorPicked(index: Int)
{...}
... so, to set that as the desired delegate, use the singleton
thatSingleton.useSnap = dinosaur
Obviously enough, this works fine.
Note too that I could easily write a little system in the singleton, so that any number of users of the protocol could dynamically register/deregister there and get the calls.
But it has obvious problems, it's not very "pattern" and seem violently non-idiomatic.
So. Am I really, doing this the right way in the Swift milieu?
Have I indeed confused myself, and there is some entirely different pattern I should be using in today's iOS, to send out such "messages to anyone who wants them?" ... maybe I shouldn't even be using a protocol?
"Send out messages to anyone who wants them" is pretty much the description of NSNotificationCenter.
True, it's not an API that's designed from the beginning for Swift patterns like closures, strong typing, and protocol-oriented programming. (As noted in other comments/answers, the open source SwiftNotificationCenter is a good alternative if you really want such features.)
However, NSNotificationCenter is robust and battle-hardened — it's the basis for thousands of messages that get sent around between hundreds of objects on each pass through the run loop.
Here's a very concise how-to for using NSNotificationCenter in Swift:
https://stackoverflow.com/a/24756761/294884
There is no "protocol based" notification mechanism in the Swift standard
libraries or runtime. A nice implementation can be found here https://github.com/100mango/SwiftNotificationCenter. From the README:
A Protocol-Oriented NotificationCenter which is type safe, thread safe
and with memory safety.
Type Safe
No more userInfo dictionary and Downcasting, just deliver the concrete
type value to the observer.
Thread Safe
You can register, notify, unregister in any thread without crash and
data corruption.
Memory Safety
SwiftNotificationCenter store the observer as a zeroing-weak
reference. No crash and no need to unregister manually.
It's simple, safe, lightweight and easy to use for one-to-many
communication.
Using SwiftNotificationCenter, a (instance of a) conforming class could register itself for example like this:
class MyObserver: SnapProtocol {
func colorPicked(i: Int) {
print("color picked:", i)
}
init() {
NotificationCenter.register(SnapProtocol.self, observer: self)
}
}
and a broadcast notification to all conforming registered observers is
done as
NotificationCenter.notify(SnapProtocol.self) {
$0.colorPicked(x)
}

Resources