Using UISheetPresentationController in SwiftUI

Published on: June 30, 2021

With iOS 15, Apple introduced the ability to easily implement a bottom sheet with UISheetPresentationController in UIKit. Unfortunately, Apple didn't extend this functionality to SwiftUI just yet (I'm hoping one of the iOS 15 betas adds this...) but luckily we can make use of UIHostingController and UIViewRepresentable to work around this limitation and use a bottom sheet on SwiftUI. In this post, I will show you a very simple implementation that might not have everything you need. After I tweeted about this hacky little workaround, someone suggested this very nice GitHub repository from Adam Foot that works roughly the same...

Read more...

Presenting a bottom sheet in UIKit with UISheetPresentationController

Published on: June 30, 2021

We've seen bottom sheets in Apple's apps for a while now, and plenty of apps have followed this pattern. If you're not sure what I mean, it's the kind of sheet that takes up just a part of the screen and can be swiped upwards to take up the whole screen or downwards to be dismissed. Here's an example from Apple's Maps app: To implement a sheet like this, we used to require third party tools, or we needed to get creative and implement this pattern ourselves. With iOS 15, Apple introduced UISheetPresentationController which allows us to implement bottom sheets...

Read more...

What are Swift Concurrency’s task local values?

Published on: June 22, 2021

If you've been following along with Swift Concurrency in the past few weeks, you might have come across the term "task local values". Task local values are, like the name suggests, values that are scoped to a certain task. These values are only available within the context they're scoped to, and they are really only supposed to be used in a handful of use cases. In this post, I will explain what task local are, and more importantly I will explain how and when they are useful. For a full rundown of task local values and their design I'd like...

Read more...

An introduction to synchronizing access with Swift’s Actors

Published on: June 14, 2021

We all know that async / await was one of this year’s big announcements WWDC. It completely changes the way we interact with concurrent code. Instead of using completion handlers, we can await results in a non-blocking way. More importantly, with the new Swift Concurrency features, our Swift code is much safer and consistent than ever before. For example, the Swift team built an all-new threading model that ensures your program doesn’t spawn more threads than there are CPU cores to avoid thread explosion. This is a huge difference from GCD where every call to async would spawn a new...

Read more...

WWDC Notes: Swift concurrency: Behind the scenes

Published on: June 10, 2021

Meet async / await, explore structured concurrency, protect mutable state with actors should be watched first. Threading model Compares GCD to Swift. It’s not built on top of GCD. It’s a whole new thread pool. GCD is very eager to bring up threads whenever we kick off work on queues. When a queue blocks its thread, a new thread will be spawned to handle work. This means that the system can overcommit with more threads than there are CPU cores. This is also called Thread explosion and can lead to memory and performance issues. There’s a lot of scheduling overhead...

Read more...

WWDC Notes: Bring Core Data concurrency to Swift and SwiftUI

Published on: June 10, 2021

Persistence everywhere Core Data takes care of many complexities to persist data. It converts in-memory graph to persisted data and takes care of all kinds of complex tasks like memory management. Core Data works on all platforms, and it’s great in Swift. Apple’s been working to make Core Data better with Swift over the years. Core Data has always cared about running code concurrently. Swift concurrency Sample app The sample app loads data from the background and persist it. Eventually it updates the view context. Insertion is done with bgctx.performAndWait() and a batch insert. performAndWait will block the calling thread...

Read more...

WWDC Notes: Discover concurrency in SwiftUI

Published on: June 9, 2021

When performing slow work, you might dispatch off of the main queue. Updating an observable object off of the main queue could result in this updating colliding with a “tick” of the run loop. This means that SwiftUI receive an objectWillChange, and attempt to redraw UI before the underlying value is updated. This will lead to SwiftUI thinking that your model is in one state, but it’s in the next. SwiftUI needs to have objectWillChange->stateChange->runloop tick in this exact order. Running your update on the main actor (or main queue pre async/await) will ensure that the state change is completed...

Read more...

WWDC Notes: Meet AsyncSequence

Published on: June 9, 2021

Map, filter, reduce, dropFirst all work in async sequences: for try await someThing in async.dropFirst() { } For example. AsyncSequence suspends on each element and receives values asynchronously from the iterator. AsyncSequences either complete with success or stop when an error is thrown. Implementing an AsyncSequence follows all the rules that a normal sequence follows. Its next() returns nil when it’s completed for example. An async iterator also consumes its underlying collection. Things like break and continue work in async sequences too. You can cancel an iteration by holding on to its Task.Handle when you wrap it in async: let...

Read more...

WWDC Notes: What’s new in SwiftUI

Published on: June 9, 2021

A good way to get started with SwiftUI is to use it for new features. SwiftUI can be mixed in with UIKit and AppKit code. It also allows you to expand into new platforms, like macOS, with little to no work. Essentially, try to do new work with SwiftUI whenever you can. Better lists SwiftUI can load images async with the new AsyncImage. This takes a URL and shows a placeholder by default. You can pass a closure to configure the loaded image with modifier, and to set a custom placeholder. There’s a new refreshable modifier. This modifier takes a...

Read more...

WWDC Notes: Protect mutable state with Swift actors

Published on: June 8, 2021

Data races make concurrency hard. They occur when two threads access the same data and at least one of them is a write. It’s trivial to write a data race, but it’s really hard to debug. Data races aren’t always clear, aren’t always reproducible, and might not always manifest in the same way. Shared mutable state is needed for a data race to occur. Value types don’t suffer from data races due to the way they work; they’re copied. When you pass an array around, copies are created. This is due to array’s value semantics. Even an object that’s a...

Read more...