andriydruk / swift-weather-app

Cross-platform Swift application for iOS/Mac/Android/Windows
MIT License
48 stars 10 forks source link

Main queue/thread issue #24

Open OlofT opened 3 years ago

OlofT commented 3 years ago

While testing this project I discovered you couldn't use DisptachQueue.main but figured out a way to make it work (see: #23). The issue now is when checking if it's the main thread, inside the main queue, you get back "false". Which probably will break stuff. Is there another way to get DisptachQueue.main working without loading the Swift library in a separate thread?

andriydruk commented 3 years ago

You can't use DisptachQueue.main for switching to the main thread. This is impossible to implement properly on non-Darwin platforms. You should implement main thread switching on each platform separately. As for Android, we use NDK Looper in Swift https://developer.android.com/ndk/reference/group/looper

OlofT commented 3 years ago

Thanks for the reply!

I don't really need to switch to the actual main thread with DisptachQueue.main, I just need it to not deadlock AND respond with "true" when inside the main queue, and asked if it's the main thread. So the ported code still behaves the same when run on Android. This far I haven't gotten both of those working at the same time.

It seems tricky to get it play along inside Android, but I will look into Looper and see if it can help me.

andriydruk commented 3 years ago

If you port iOS code you should rid of all Dispatch.mainQueue, because it wouldn't work correct on all non-Darwin platforms. Thread.isMainThread always will be false in this queue.

We basically use kind of global func scheduleOnMainThread(_ block: @escaping () -> Void) and every platform has own implementation

OlofT commented 2 years ago

Well, that is unfortunate. I would much like to keep the non-UI code as intact and untouched as possible (some refactoring is ok). Especially with Swift 5.5 and Actors you want to be able to take advantage of those features, and at the same time you don't want to fiddle with the inner workings of threads and queues.

I understand there are differences between platforms and it might not be possible to get it working.

andriydruk commented 2 years ago

I guess non-UI code should know nothing about UI-thread because it's UI 😅 Every platform has its own concept of how a developer should interact with this particular platform's UI library. And there is no way to create one unified API that will work for every one 🤷‍♂️

OlofT commented 2 years ago

Not really, it still needs to know on what thread to change UI-related properties to not mess up UI-states.

Or one can think of it this way; we have this concept of "main". It does not need to be regarding UI but could be any sort of processing that you need to do on the same thread or queue. We can agree among ourselves that we only perform such tasks on "main". With this in mind, we don't need to care if the UI-thread and "main" are the same on all platforms (that can be platform specific) but we still want to reason about "main", having a main-actor, queue or thread to perform work on. On iOS, apps can continue to work the way they have always done, and other platforms can handle main/UI-thread interop as it suits that particular platform. Data being downloaded don't really need to care as long as it sends its result to the main thread, it knows that some other part of the system will take care of the changes without messing up the UI or crash, etc. And if we do other tasks we know that they can't interfere with each other since main is a unique queue/thread.

The point is to leverage as much as possible from Swift, to maximize the amount of code-reuse, and I believe that being able to use main queues/threads is quite important for that to happen. Sure, one could see rewriting all multithreading code as a needed step in order for that to happen, but I would much rather find a solution that fits with how Swift works.

Perhaps its impossible, but I sure hope not!

andriydruk commented 2 years ago

We probably have different understanding of non-UI code. You could check how main thread issue handled in this repository: all shared code know nothing about UI or UI-properties.

I understood your position. You would love to share as much as possible between platforms. And it would be great if we have DispatchMain and SwiftUI and lot of other thing from Apple. But current situation is different. If proper DispatchQueue.main implementation will be available in swift-corelibs-libdispatch we would definitely rebuild toolchain with this changes.

If you want take part in development of this feature I think you should start from Dispatch. As I remember this is last discussion about DispatchMain on Android: https://github.com/apple/swift-corelibs-libdispatch/pull/299

OlofT commented 2 years ago

Thanks! That discussion brings the exact points I was trying to make. The solution is also where my thoughts where going.

I think DispatchMain is a more integral part of Swift than SwiftUI (which I don't see a place for on Android). Anyhow, thanks again, I'll see what I can do about it.

andriydruk commented 2 years ago

Hi, I made a small investigation on dispatch and corefoundation main thread mechanism and it doesn't look so difficult to implement on Android.

I added a basic implementation of running RunLoop on the main thread in the AndroidNDK library. To set up the main run loop please call setupAndroidMainRunLoop on application start. It will work only with JVM, if you would like to set up the main queue in tests you should create AndroidLooper first (see tests from this repo).

PS I still don't see a place for the main queue in this repo, because I'm trying to build an app for all platforms including Linux and Windows (not sure I want to deal with the main queue on these platforms)

OlofT commented 2 years ago

Wow, and thank you! This looks like exactly what I need!

To be honest it felt a bit much to get into all of the underpinnings of the NDK and Dispatch... Thanks again :)