| # Objective-C threading considerations | |
| Multithreading is one of the trickiest parts of interop between Objective-C | |
| and Dart. This is due to the relationship between Dart isolates and OS | |
| threads, and the way Apple's APIs handle multithreading: | |
| 1. Dart isolates are not the same thing as threads. Isolates run on threads, | |
| but aren't guaranteed to run on any particular thread, and the VM might | |
| change which thread an isolate is running on without warning. There is an | |
| [open feature request](https://github.com/dart-lang/sdk/issues/46943) | |
| to enable isolates to be pinned to specific threads. | |
| 2. While FFIgen supports converting Dart functions to Objective-C blocks, | |
| most Apple APIs don't make any guarantees about which thread a callback | |
| will run on. | |
| 3. Most APIs that involve UI interaction can only be called on the main | |
| thread, also called the platform thread in Flutter. | |
| 4. Many Apple APIs are [not thread safe]( | |
| https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html). | |
| The first two points mean that a block created in one isolate might be | |
| invoked on a thread running a different isolate, or no isolate at all. | |
| Depending on the type of block you are using, this could cause your app to | |
| crash. When a block is created, the isolate it was created in is its owner. | |
| Blocks created using `FooBlock.fromFunction` must be invoked on the | |
| owner isolate's thread, otherwise they will crash. Blocks created using | |
| `FooBlock.listener` or `FooBlock.blocking` can be safely invoked from any | |
| thread, and the function they wrap will (eventually) be invoked inside the | |
| owner isolate, though these constructors are only supported for blocks that | |
| return `void`. `FooBlock.blocking` may add support for non-`void` return values | |
| in future, if there is user demand for it. | |
| The third point means that directly calling some Apple APIs using the | |
| generated Dart bindings might be thread unsafe. This could crash your app, or | |
| cause other unpredictable behavior. In recent versions of Flutter, the main | |
| isolate runs on the platform thread, so this isn't an issue when invoking | |
| these thread-locked APIs from the main isolate. If you need to invoke these | |
| APIs from other isolates, or you need to support older versions of flutter, | |
| you can use the [`runOnPlatformThread`]( | |
| https://api.flutter.dev/flutter/dart-ui/runOnPlatformThread.html) function. | |
| Regarding the last point, although Dart isolates can switch threads, they | |
| only ever run on one thread at a time. So, the API you are interacting with | |
| doesn't necessarily have to be thread safe, as long as it is not thread | |
| hostile, and doesn't have constraints about which thread it's called from. | |
| You can safely interact with Objective-C code as long as you keep these | |
| limitations in mind. |