Post APyRNS71WVaAwZCMls by Alexbbrown@hachyderm.io
(DIR) More posts by Alexbbrown@hachyderm.io
(DIR) Post #APyRNR5vJ76lmrfyPw by Alexbbrown@hachyderm.io
2022-11-25T06:11:02Z
1 likes, 0 repeats
:swift: Unconventional Shapes #1 - Actors with AsyncSequences#SwiftUI apps use threads for UI, model and network. This can glitch and crash. Should you cross your fingers, or add complex locks?#Swift #Concurrency can help! Actors are a new way to code the data model in your swift App. Actor methods give safe async access to one value from the model's data.What if you need more than one result, like streamed posts from the network?Use #AsyncSequence! Here's today's Unconventional Shape:
(DIR) Post #APyRNS71WVaAwZCMls by Alexbbrown@hachyderm.io
2022-11-25T07:27:51Z
0 likes, 0 repeats
This is my first proper toot 🎉 - and I want to find out if there's appetite for exploring some of the corners of :swift: #SwiftLang that can slow folks down once they graduate from the basics.In the replies I'll explore a little more of how the solution works, and how it can be used
(DIR) Post #APyRNT2S4zWHog4EHg by Alexbbrown@hachyderm.io
2022-11-25T07:27:54Z
0 likes, 0 repeats
📖 An actor is a new kind of storage in swift, joining `class` and `struct` as a way to store and share structured data and behaviour.In particular, most methods (funcs) in an actor are implicitly async. From the perspective of the caller, they asynchronously return a value. actor MyActor { func compute() -> Int { return 6 * 7 }}func(a: MyActor) { Task { // this call might take a while, so we 'await'. let answer = await a.compute() }}
(DIR) Post #APyRNUWcYJFKQXBpwm by Alexbbrown@hachyderm.io
2022-11-25T07:27:55Z
0 likes, 0 repeats
An async function represents delayed work. When it does eventually return, it returns *all at once*.But some data doesn't arrive like that - it returns a little at a time - eg:* downloading a large file in small bits* instant message replies from your buddy* photos of world cup goals as they happen.In Swift #Concurrency we transmit values like this as as `AsyncStream` or other types which conform to `protocol AsyncSequences`https://developer.apple.com/documentation/swift/asyncstream/
(DIR) Post #APyRNVY4kO0JbKsVqy by Alexbbrown@hachyderm.io
2022-11-25T07:27:56Z
0 likes, 0 repeats
The very best thing about AsyncSequences is that there is a really easy and familiar way to use them in code:It's the humble `for` loop…for try await goalPhoto in footballGoals() { displayInWindow(goalPhoto)}with the keyword `await` added to recognise that your code might have to wait a long time…⏱️… until the next message arrives (come ON you football guys, score already ⚽️…🥅 )Tech Note: await can cause code to switch threads or be rentrant.Now watch this:https://developer.apple.com/wwdc21/10058
(DIR) Post #APyRNWRjPSWWNwuxbU by Alexbbrown@hachyderm.io
2022-11-25T07:27:56Z
0 likes, 0 repeats
But `AsyncSequence` values can be hard to construct.And actors have subtle requirements which make this harder - like `Sendable`As you learn more, I'm sure you will find many ways to get and create AsyncSequences, including getting them from other APIs, and writing your own.But for the moment I want to show you just one quick way that works. It may not be the optimal way, and might not work for all uses, but you can try it out
(DIR) Post #APyRNXCAcnfchye2zI by Alexbbrown@hachyderm.io
2022-11-25T07:27:57Z
0 likes, 0 repeats
AsyncSequence is Apple's simpler, funner successor to another great technology called #Combine.The API is almost identical, and this means you can easily create AsyncSequences from existing Combine Publishers.So that's how my example works:1. Create a sample Combine Publisher of Integers (Int)2. Erase it to`some Publisher<Int, Never>` (actually this step is automatic)3. Convert it to AsyncThrowingPublisher4. return it from the actor as AsyncThrowingPublisher<some Publisher<Int, Never>>
(DIR) Post #APyRNY57KVcfSOLvdI by Alexbbrown@hachyderm.io
2022-11-25T07:28:00Z
0 likes, 0 repeats
actor MyActor { func numbers() -> AsyncThrowingPublisher<some Publisher<Int, Never>> { (1...10) // an array .publisher // combine publisher .drip(every: 0.5) // same but slower .values // a AsyncSequence (actually AsyncThrowingPublisher) }}call it like this:do { for try await value in await anActor.numbers() { self.numbers += [value] } } catch { self.numbers += [-1]}note that 'await' is required twice, once for the actor, and once for the sequence!
(DIR) Post #APyRNYtSJLt9yVu85w by Alexbbrown@hachyderm.io
2022-11-25T07:28:02Z
0 likes, 0 repeats
You might be asking : how can I use this?But luckily, there's loads of great ways to make a combine Publisher that you already have access to.Notifications in Notification Center: https://developer.apple.com/documentation/combine/routing-notifications-to-combine-subscribersTimers: https://developer.apple.com/documentation/combine/replacing-foundation-timers-with-timer-publishersKVO: https://developer.apple.com/documentation/combine/performing-key-value-observing-with-combineFetching Data from a Internet URL: https://developer.apple.com/documentation/foundation/urlsession/processing_url_session_data_task_results_with_combine/
(DIR) Post #APyRNZgNNT1KQEnCLY by Alexbbrown@hachyderm.io
2022-11-25T07:28:03Z
0 likes, 0 repeats
Future steps:As you get better at using Actors with SwiftUI, you may find other AsyncStreams and AsyncSequences that aren't based on combine.You'll need to tweak your approach a bit. Sadly, it's not as easy as writingsome AsyncSequence<Int> // this does not workBut you can access the actual type of the Sequence and return that. You'll need to play around a bit, and that's outside the scope of this article.Good luck!
(DIR) Post #APyRNba4JtACJFrBnE by Alexbbrown@hachyderm.io
2022-11-25T07:28:04Z
0 likes, 0 repeats
Note: The rules on Sendable types are quickly evolving in Swift. I tested this example in Swift Playgrounds 4.2.1 and didn't get any compiler warnings.However, you might get warnings in Xcode with the same code. If so, sorry. Let me know and I'll take a look if I get time.
(DIR) Post #APyRNcFtoMckOzQazg by Alexbbrown@hachyderm.io
2022-11-25T07:28:05Z
0 likes, 0 repeats
You should now have everything you need to try it out for yourself. For the source code, check out the ALT Text for the images in the first post. It's not quite clear to me the best way to add code to Toots. LMK what you would prefer in future.I'd like to get code examples