Vatsal Manot

Read this first

How to use UIApplicationDelegateAdaptor

With SwiftUI 2.0, UIApplicationDelegate is a thing of the past… well, maybe not. While the new App protocol and friends provide great, declarative abstractions over UIKit/AppKit app lifecycle APIs, their shortcomings may become evident when faced with complex scenarios - such as handling remote notifications, or handling shortcuts.

Fortunately, SwiftUI 2.0 provides us with a bridge between our two worlds:

/// A property wrapper that is used in `App` to provide a delegate from UIKit.
@available(iOS 14.0, tvOS 14.0, *)
@available(OSX, unavailable)
@available(watchOS, unavailable)
@propertyWrapper public struct UIApplicationDelegateAdaptor<DelegateType> : DynamicProperty where DelegateType : NSObject, DelegateType : UIApplicationDelegate {

    /// The underlying delegate.
    public var wrappedValue: DelegateType { get }

    /// Creates an `UIApplicationDelegateAdaptor` using a UIKit
...

Continue reading →


My SwiftUI wishlist for WWDC 2020

Let me start by saying that SwiftUI is simply amazing.

I’ve been working on an open-source framework called SwiftUIX for about a year now, with the ambitious goal of filling up certain gaps while we wait for Apple’s annual release cycle. Here are a few of the things I’d like to see in SwiftUI 2.0:

1. Presentation

While SwiftUI offers some pretty powerful primitives to cover the most commonly used presentation styles such as sheets, action sheets, alerts & popovers - it leaves much to be desired in terms of customizability.

Here are things I’d like to see:

  • A port for UIModalPresentationStyle (my attempt at this can be found here).
  • A port for UIWindow (my port here).
  • A port for transitioning delegates.
  • A port for UIViewControllerTransitioningDelegate.

2. Container View Interactors

You may have come across PresentationMode while working with SwiftUI.

public struct PresentationMode
...

Continue reading →


Inlining @Environment access in SwiftUI

The @Environment modifier in SwiftUI is a core data-flow primitive, that allows one to access environment values set by the parent.

Example usage:

struct Foo: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Group {
            if colorScheme == .light {
                Text("Light")
            } else {
                Text("Dark")
            }
        }
    }
}

This is all well and good - but note that @Environment is implemented as a property wrapper and cannot be used without a housing View structure.

In prototyping code heavily reliant on @Environment, this can feel cumbersome and boilerplate-y. Hence, I wrote a simple generic wrapper to solve this problem:

public struct EnvironmentValueAccessView<EnvironmentValue, Content: View>: View {
    private let keyPath: KeyPath<EnvironmentValues, EnvironmentValue>
    private let content:
...

Continue reading →


Fixing NSManagedObject’s ObservableObject conformance

In working with SwiftUI you may have noticed that NSManagedObject is not a particularly correct implementation of ObservableObject. Your NSManagedObject does not publish changes when any of its @NSManaged properties are mutated.

There’s an easy fix for this:

open class ManagedObject: NSManagedObject {
    override public func willChangeValue(forKey key: String) {
        super.willChangeValue(forKey: key)

        objectWillChange.send()
    }
}

Simply tweak your model classes to inherit from ManagedObject, instead of NSManagedObject, et voilà  - your managed objects will behave as expected.

Explanation

This essentially hooks into a core NSManagedObject method - willChangeValue(forKey:) and overrides it to also publish changes to the objectWillChange publisher when invoked.

Continue reading →


How to fix Segmentation fault: 11 with @propertyWrapper

I recently encountered a small but annoying bug with property wrappers in Swift 5.1. When building the following code for archiving/profiling:

@propertyWrapper
public struct Foo<T> {
    public let wrappedValue: T?

    public init(wrappedValue: T? = nil) {
        self.wrappedValue = wrappedValue
    }
}

The compiler throws a Segmentation fault: 11:

While running pass 0 SILModuleTransform "SerializeSILPass".

The fix is rather simple. Simply break init(wrappedValue:) (which contains a default nil value) into two separate initializers, like so:

@propertyWrapper
public struct Foo<T> {
    public let wrappedValue: T?

    public init(wrappedValue: T?) {
        self.wrappedValue = wrappedValue
    }

    public init() {
        self.init(wrappedValue: nil)
    }
}

Continue reading →


Removing List’s cell separators in SwiftUI

Currently, as of Xcode 11.1, Apple provides no way for developers to specify a cell separator style for SwiftUI’s List.

Having run into this issue myself, I finally stumbled upon a workaround:

UITableView.appearance().separatorStyle = .none

List seems to respect the UITableView appearance proxy. While this may change in future iOS releases, it’s a good enough solution for the time being.

There is one major caveat - UITableView.appearance() affects the appearance of all Lists in the application. How can we restrict our desired appearance to a single screen?

We utilize a view’s lifecycle events, View.onAppear and View.onDisappear, to set and then unset our custom appearance for a given view.

List {
    Text("a")
    Text("b")
    Text("c")
    Text("d")
}.onAppear {
    UITableView.appearance().separatorStyle = .none
}.onDisappear {
    UITableView.appearance().separatorStyle =
...

Continue reading →


Data Flow Through SwiftUI

This article may be considered a condensed version of the (highly-recommended) WWDC19 talk, “Data Flow Through SwiftUI”, along with a few thoughts and insights of my own. It represents my own, current understanding of data flow in SwiftUI, derived from experimentation over the past two months.

Let’s start with an important quote from the aforementioned talk:

Data is a first class citizen in SwiftUI.

This is the crux of what makes SwiftUI not only so beautifully elegant, but also extremely ergonomic.

The Two Key Principles

SwiftUI is designed to be declarative and functional. As such, data flow in SwiftUI revolves around two key principles:

  • Reading data creates dependencies.
  • Every piece of data has a source of truth.

This all seems quite abstract, and so we shall revisit a popular definition for declarative programming:

“You know, imperative programming is like* how you do...

Continue reading →


For Antara

The mellow embrace of blue,
With a silent whisper of white,
Dipped gently in lavender,
Flowing fill into sight.

The quiet stretch of infinity,
Peering deep into the soul,
An ocean of serenity,
Washing away the toll.

An impossible canvas beheld,
Each stroke brushed past,
Dark painted darker,
A memory etched last.

Persuasive, pristine, perfect,
A shapeless void in flight;
That, my dear,
Is the beauty of night.

View →


Reimplementing SwiftUI’s deprecated relative view sizing functions.

With Xcode 11 beta 4, Apple deprecated SwiftUI’s View.relativeSize function (as well as View.relativeWidth and View.relativeHeight).

The relativeWidth(_:), relativeHeight(_:), and relativeSize(width:height:) modifiers are deprecated. Use other modifiers like frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:) instead. (51494692)

For those dismayed by these changes, there’s an easy reimplementation available using GeometryReader:

extension View {
    public func relativeHeight(
        _ ratio: CGFloat,
        alignment: Alignment = .center
    ) -> some View {
        GeometryReader { geometry in
            self.frame(
                height: geometry.size.height * ratio,
                alignment: alignment
            )
        }
    }

    public func relativeWidth(
        _ ratio: CGFloat,
        alignment: Alignment = .center
    ) -> some View {
...

Continue reading →


PresentationLink broken in Xcode 11 beta 3

PresentationLink (in SwiftUI) seems to be broken in Xcode 11 beta 3.

It succeeds in presenting a modal view controller the first time, but stops working thereafter.

As noted in this StackOverflow post, this seems to occur when embedding a PresentationLink within a NavigationView, with the following warning printed to console:

[WindowServer] display_timer_callback: unexpected state (now:1abc3d3ccc7 < expected:1abc3d91a0f)

This bug has existed since Xcode 11 beta 1 (back when PresentationLink was called PresentationButton), which is quite alarming given the fact that we’re on beta 3 now.

I’ve written a quick and dirty workaround for this:

private enum SetPresentedViewKey: EnvironmentKey {
    static var defaultValue: (AnyView?) -> () {
        fatalError()
    }
}

private extension EnvironmentValues {
    var setPresentedView: (AnyView?) -> () {
        get {
...

Continue reading →