tag:vmanot.com,2014:/feedVatsal Manot2020-06-12T15:36:54-07:00Vatsal Manothttps://vmanot.comSvbtle.comtag:vmanot.com,2014:Post/my-swiftui-wishlist-for-wwdc-20202020-06-12T15:36:54-07:002020-06-12T15:36:54-07:00My SwiftUI wishlist for WWDC 2020<p>Let me start by saying that SwiftUI is simply amazing.</p>
<p>I’ve been working on an open-source framework called <a href="https://github.com/SwiftUIX/SwiftUIX">SwiftUIX</a> 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:</p>
<h2 id="1-presentation_2">1. Presentation <a class="head_anchor" href="#1-presentation_2">#</a>
</h2>
<p>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.</p>
<p>Here are things I’d like to see:</p>
<ul>
<li>A port for <code class="prettyprint">UIModalPresentationStyle</code> (my attempt at this can be found <a href="https://github.com/SwiftUIX/SwiftUIX/blob/master/Sources/Intramodular/Presentation/ModalViewPresentationStyle.swift">here</a>).</li>
<li>A port for <code class="prettyprint">UIWindow</code> (my port <a href="https://github.com/SwiftUIX/SwiftUIX/blob/master/Sources/Intermodular/Helpers/SwiftUI/WindowOverlay.swift">here</a>).</li>
<li>A port for transitioning delegates.</li>
<li>A port for <code class="prettyprint">UIViewControllerTransitioningDelegate</code>.</li>
</ul>
<h2 id="2-container-view-interactors_2">2. Container View Interactors <a class="head_anchor" href="#2-container-view-interactors_2">#</a>
</h2>
<p>You may have come across <a href="https://developer.apple.com/documentation/swiftui/presentationmode"><code class="prettyprint">PresentationMode</code></a> while working with SwiftUI.</p>
<pre><code class="prettyprint lang-swift">public struct PresentationMode {
/// Indicates whether a view is currently presented.
public var isPresented: Bool { get }
/// Dismisses the view if it is currently presented.
///
/// If `isPresented` is false, `dismiss()` is a no-op.
public mutating func dismiss()
}
</code></pre>
<p>It is exposed via <code class="prettyprint">EnvironmentValues</code> as a <code class="prettyprint">Binding</code> to a <code class="prettyprint">PresentationMode</code> instance. Any sheet presented by SwiftUI can be dismissed by referencing this environment value within the presented view, and invoking <code class="prettyprint">dismiss()</code> upon it.</p>
<p>I think this is a <strong>fantastic</strong> solution to the problem of not being able to reference views/view controllers directly, but still being able to provide a meaningful way of interacting with them. </p>
<p>Consider <a href="https://github.com/SwiftUIX/SwiftUIX/blob/master/Sources/Intramodular/Pagination/PaginationView.swift"><code class="prettyprint">PaginationView</code></a>, essentially my take on a port of <code class="prettyprint">UIPageViewController</code>. I asked myself, what would an API for programmatic pagination look like?</p>
<p>Drawing inspiration from <code class="prettyprint">PresentationMode</code> - I came up with the concept of a <a href="https://github.com/SwiftUIX/SwiftUIX/blob/master/Sources/Intramodular/Control/Interactors/ProgressionController.swift">“progression controller”</a>. Essentially an opaque interface that exposes two key functions:</p>
<pre><code class="prettyprint lang-swift">protocol ProgressionController {
func moveToNext()
func moveToPrevious()
}
</code></pre>
<p>This could be exposed via an environment value (in my case <code class="prettyprint">@Environment(\.progressionController</code>)) that could essentially let any child views of the pagination view programmatically navigate back/forth. This <code class="prettyprint">ProgressionController</code> could be expanded to fit in more concepts - such as page indices etc. </p>
<p>The beauty of <code class="prettyprint">PresentationMode</code> lies in the fact that it decouples the presenter into a <em>concept</em> of a presenter. It lets the presented view have access to one, and only one piece of functionality - presentation. I’d love to see more “interactors” like these. <code class="prettyprint">scrollToBottom</code> and <code class="prettyprint">scrollToTop</code> for <code class="prettyprint">ScrollView</code>, perhaps, by way of a <code class="prettyprint">Scroller</code> struct. The possibilities are quite exciting.</p>
<h2 id="3-more-dynamic-properties_2">3. More Dynamic Properties <a class="head_anchor" href="#3-more-dynamic-properties_2">#</a>
</h2>
<p><code class="prettyprint">@Environment</code>, <code class="prettyprint">@EnvironmentObject</code>, <code class="prettyprint">@ObservedObject</code>, <code class="prettyprint">@Published</code> & <code class="prettyprint">@State</code> are amazing primitives. I feel like this concept can be built upon and fledged out a lot further. Consider <a href="https://github.com/SwiftUIX/SwiftUIX/blob/master/Sources/Intramodular/Dynamic%20Properties/TimerState.swift"><code class="prettyprint">@TimerState</code></a> - a simple wrapper over <code class="prettyprint">@State</code> that provides a declarative and easy-to-use API for timers in Swift views. </p>
<p>The following view will refresh every 1 second. <code class="prettyprint">@TimerState</code> provides an auto-incrementing <code class="prettyprint">Int</code> to reference the current “tick” of a <code class="prettyprint">Timer</code>.</p>
<pre><code class="prettyprint">struct ContentView: View {
@TimerState(interval: 1) var tick: Int
var body: some View {
Text("\(tick) second(s) have elapsed")
}
}
</code></pre>
<p>There are obviously many more things I’d like to see in SwiftUI 2.0, such as missing container views (collection views, pagination views etc.) and missing controls (activity indicators, refresh controls, checkboxes) - but these are some areas/concepts that seemed extremely exciting to me, and I’d love to see them developed further.</p>
tag:vmanot.com,2014:Post/inlining-environment-access-in-swiftui2020-05-27T07:50:48-07:002020-05-27T07:50:48-07:00Inlining @Environment access in SwiftUI<p>The <code class="prettyprint">@Environment</code> modifier in SwiftUI is a core data-flow primitive, that allows one to access environment values set by the parent.</p>
<p>Example usage:</p>
<pre><code class="prettyprint lang-swift">struct Foo: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
Group {
if colorScheme == .light {
Text("Light")
} else {
Text("Dark")
}
}
}
}
</code></pre>
<p>This is all well and good - but note that <code class="prettyprint">@Environment</code> is implemented as a property wrapper and cannot be used without a housing <code class="prettyprint">View</code> structure.</p>
<p>In prototyping code heavily reliant on <code class="prettyprint">@Environment</code>, this can feel cumbersome and boilerplate-y. Hence, I wrote a simple generic wrapper to solve this problem:</p>
<pre><code class="prettyprint lang-swift">public struct EnvironmentValueAccessView<EnvironmentValue, Content: View>: View {
private let keyPath: KeyPath<EnvironmentValues, EnvironmentValue>
private let content: (EnvironmentValue) -> Content
@Environment var environmentValue: EnvironmentValue
public init(
_ keyPath: KeyPath<EnvironmentValues, EnvironmentValue>,
@ViewBuilder content: @escaping (EnvironmentValue) -> Content
) {
self.keyPath = keyPath
self.content = content
self._environmentValue = .init(keyPath)
}
public var body: some View {
content(environmentValue)
}
}
</code></pre>
<p>With <code class="prettyprint">EnvironmentValueAccessView</code> now, we can express our example code as a simple inline expression:</p>
<pre><code class="prettyprint lang-swift"> EnvironmentValueAccessView(\.colorScheme) { colorScheme in
if colorScheme == .light {
Text("Light")
} else {
Text("Dark")
}
}
</code></pre>
tag:vmanot.com,2014:Post/fixing-nsmanagedobject-s-observableobject-conformance2020-05-10T12:42:16-07:002020-05-10T12:42:16-07:00Fixing NSManagedObject's ObservableObject conformance<p>In working with SwiftUI you may have noticed that <code class="prettyprint">NSManagedObject</code> is not a particularly correct implementation of <code class="prettyprint">ObservableObject</code>. Your <code class="prettyprint">NSManagedObject</code> <em>does not</em> publish changes when any of its <code class="prettyprint">@NSManaged</code> properties are mutated. </p>
<p>There’s an easy fix for this: </p>
<pre><code class="prettyprint lang-swift">open class ManagedObject: NSManagedObject {
override public func willChangeValue(forKey key: String) {
super.willChangeValue(forKey: key)
objectWillChange.send()
}
}
</code></pre>
<p>Simply tweak your model classes to inherit from <code class="prettyprint">ManagedObject</code>, instead of <code class="prettyprint">NSManagedObject</code>, et voilà - your managed objects will behave as expected.</p>
<h2 id="explanation_2">Explanation <a class="head_anchor" href="#explanation_2">#</a>
</h2>
<p>This essentially hooks into a core <code class="prettyprint">NSManagedObject</code> method - <a href="https://developer.apple.com/documentation/objectivec/nsobject/1416222-willchangevalue"><code class="prettyprint">willChangeValue(forKey:)</code></a> and overrides it to also publish changes to the <code class="prettyprint">objectWillChange</code> publisher when invoked.</p>
tag:vmanot.com,2014:Post/how-to-fix-segmentation-fault-11-with-propertywrapper2020-01-01T06:40:12-08:002020-01-01T06:40:12-08:00How to fix Segmentation fault: 11 with @propertyWrapper<p>I recently encountered a small but annoying bug with property wrappers in Swift 5.1. When building the following code for archiving/profiling:</p>
<pre><code class="prettyprint lang-swift@propertyWrapper">@propertyWrapper
public struct Foo<T> {
public let wrappedValue: T?
public init(wrappedValue: T? = nil) {
self.wrappedValue = wrappedValue
}
}
</code></pre>
<p>The compiler throws a <code class="prettyprint">Segmentation fault: 11</code>:</p>
<pre><code class="prettyprint">While running pass #0 SILModuleTransform "SerializeSILPass".
</code></pre>
<p>The fix is rather simple. Simply break <code class="prettyprint">init(wrappedValue:)</code> (which contains a default <code class="prettyprint">nil</code> value) into two separate initializers, like so:</p>
<pre><code class="prettyprint lang-swift@propertyWrapper">@propertyWrapper
public struct Foo<T> {
public let wrappedValue: T?
public init(wrappedValue: T?) {
self.wrappedValue = wrappedValue
}
public init() {
self.init(wrappedValue: nil)
}
}
</code></pre>
tag:vmanot.com,2014:Post/removing-list-s-cell-separators-in-swiftui2019-10-14T07:18:28-07:002019-10-14T07:18:28-07:00Removing List's cell separators in SwiftUI<p>Currently, as of Xcode 11.1, Apple provides no way for developers to specify a cell separator style for SwiftUI’s <code class="prettyprint">List</code>. </p>
<p>Having run into this issue myself, I finally stumbled upon a workaround:</p>
<pre><code class="prettyprint lang-swift">UITableView.appearance().separatorStyle = .none
</code></pre>
<p><code class="prettyprint">List</code> seems to respect the <code class="prettyprint">UITableView</code> appearance proxy. While this may change in future iOS releases, it’s a good enough solution for the time being. </p>
<p>There is one major caveat - <code class="prettyprint">UITableView.appearance()</code> affects the appearance of <u>all</u> <code class="prettyprint">List</code>s in the application. How can we restrict our desired appearance to a single screen? </p>
<p>We utilize a view’s lifecycle events, <code class="prettyprint">View.onAppear</code> and <code class="prettyprint">View.onDisappear</code>, to set and then unset our custom appearance for a given view.</p>
<pre><code class="prettyprint lang-swift">List {
Text("a")
Text("b")
Text("c")
Text("d")
}.onAppear {
UITableView.appearance().separatorStyle = .none
}.onDisappear {
UITableView.appearance().separatorStyle = .singleLine
}
</code></pre>
<p>While this works, it seems rather unwieldly and odd. We can further simplify this code by wrapping part of it in a <code class="prettyprint">ViewModifier</code>. </p>
<pre><code class="prettyprint lang-swift">public struct ListSeparatorStyleNoneModifier: ViewModifier {
public func body(content: Content) -> some View {
content.onAppear {
UITableView.appearance().separatorStyle = .none
}.onDisappear {
UITableView.appearance().separatorStyle = .singleLine
}
}
}
extension View {
public func listSeparatorStyleNone() -> some View {
modifier(ListSeparatorStyleNoneModifier())
}
}
</code></pre>
<p>As you can see, we’ve wrapped our appearance setting code into a neat little view modifier. Our example can now be reduced to:</p>
<pre><code class="prettyprint lang-swift">List {
Text("a")
Text("b")
Text("c")
Text("d")
}.listSeparatorStyleNone()
</code></pre>
<p><strong>Note:</strong> There is still one issue that we haven’t solved. While view lifecycle events allow us to set/unset the appearance, they affect <em>all</em> views in a given screen. The subject of our modifier must be destroyed for the appearance to restore to its original state, and thus we cannot prevent it from affecting sibling views. We will tackle this problem in a future post.</p>
tag:vmanot.com,2014:Post/data-flow-through-swiftui2019-08-19T10:28:22-07:002019-08-19T10:28:22-07:00Data Flow Through SwiftUI<p>This article may be considered a condensed version of the (highly-recommended) WWDC19 talk, <a href="https://developer.apple.com/videos/play/wwdc2019/226/">“Data Flow Through SwiftUI”</a>, 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.</p>
<p>Let’s start with an important quote from the aforementioned talk:</p>
<blockquote class="short">
<p>Data is a first class citizen in SwiftUI.</p>
</blockquote>
<p>This is the crux of what makes SwiftUI not only so beautifully elegant, but also extremely ergonomic. </p>
<h2 id="the-two-key-principles_2">The Two Key Principles <a class="head_anchor" href="#the-two-key-principles_2">#</a>
</h2>
<p>SwiftUI is designed to be declarative and functional. As such, data flow in SwiftUI revolves around two key principles:</p>
<ul>
<li>Reading data creates dependencies.</li>
<li>Every piece of data has a source of truth.</li>
</ul>
<p>This all seems quite abstract, and so we shall revisit a popular definition for declarative programming:</p>
<blockquote class="short">
<p>“You know, imperative programming is like* <strong>how</strong> <em>you do something, and declarative programming is more like</em> <strong>what</strong> <em>you do, or something.”</em></p>
</blockquote>
<p>What does this mean, when contextualized in actual Cocoa/Cocoa Touch development? If you’re ever worked with UIKit (or AppKit), you know that the traditional method of handling events or receiving data input is by the way of delegates. These delegates inform an internal or external state, managed through view controllers, which also bear the responsibility of configuring and reconfiguring child views.</p>
<p>As your view controller grows in complexity, the number of manual synchronizations and invalidations that have to be made increase sharply. A switch may show/hide a view, a slider may set the value of a label, a picker may drive an image displayed above it, etc. It gets even worse when you have complex, compound predicate based logic, such as a condition satisfied by a certain permutation of toggles in a form, updates from a real-time database.</p>
<p>SwiftUI tackles this problem through some powerful design choices:</p>
<ul>
<li>Views are a <strong>function over data</strong>. Every single implementation for <code class="prettyprint">body</code> that you will write for a SwiftUI view will be <em>computed</em> and not preconfigured.</li>
<li>Views are <strong>value types</strong>. They may not be indirectly referenced or mutated by other views (as UIKit and AppKit views permit), only ever initialized in the computed <code class="prettyprint">body</code> getter. This is extremely import as a View <strong>must</strong> define all its possible dependencies, which are passed through the view’s initializer.</li>
<li>The entire SwiftUI framework is oriented around <strong>composition of small pieces</strong>. This is an actual quote, verbatim from the WWDC19 talk <a href="https://developer.apple.com/videos/play/wwdc2019/216/">SwiftUI Essentials</a>. What this also means is that data is scoped by ancestry, passed from a parent to a child. The importance of this aspect will become clearer further along the article.</li>
<li>
<strong>Views are models</strong> of <em>what</em> to be rendered, not the actual render data itself. A SwiftUI <code class="prettyprint">View</code> holds no direct or indirect reference to say, the pixel buffer or graphics context that it is actually mapped to during the runtime of your app.</li>
</ul>
<p>Consider the following example:</p>
<pre><code class="prettyprint lang-swift">struct ContentView: View {
let text: String
var body: some View {
Text(text)
}
}
</code></pre>
<p>Our <code class="prettyprint">ContentView</code> has no means of mutating <code class="prettyprint">Text</code>, only a means of initializing it. In turn, the view initializing <code class="prettyprint">ContentView</code> shall have no means of mutating <code class="prettyprint">ContentView</code>, but only that of passing down a single variable <code class="prettyprint">text</code>. </p>
<p>This is all well and good, but real world applications require views capable of mutating themselves on screen. The example above simply demonstrates the display of static data. How are SwiftUI views to mutate themselves, if they are value types and the <code class="prettyprint">body</code> is a <code class="prettyprint">nonmutating</code> getter? Let us progress to <strong>dynamic view properties</strong>. </p>
<h2 id="dynamic-view-properties_2">Dynamic View Properties <a class="head_anchor" href="#dynamic-view-properties_2">#</a>
</h2>
<p>If you’ve ever seen or written SwiftUI code, you must have noticed by now that the framework offers various property wrappers to represent <strong>mutable</strong> data stored in your application’s view hierarchy:</p>
<ul>
<li><code class="prettyprint">@State</code></li>
<li><code class="prettyprint">@ObservedObject</code></li>
<li><code class="prettyprint">@EnvironmentObject</code></li>
<li><code class="prettyprint">@GestureState</code></li>
<li><code class="prettyprint">@Binding</code></li>
</ul>
<p>These are what are known as <strong>dynamic view properties</strong> (or just <strong>dynamic properties</strong>, as of Xcode 11 beta 5. All these structures share a conformance to SwiftUI’s <code class="prettyprint">DynamicProperty</code> protocol (formerly <code class="prettyprint">DynamicViewProperty</code>).</p>
<p>Here is the <a href="https://developer.apple.com/documentation/swiftui/dynamicproperty">official documentation</a> on <code class="prettyprint">DynamicProperty</code>:</p>
<blockquote>
<p>A stored variable that updates an external property of a view.</p>
<p>The view gives values to these properties prior to recomputing the view’s <a href="https://developer.apple.com/documentation/swiftui/view/3278523-body"><code class="prettyprint">body</code></a>.</p>
</blockquote>
<p>And here is the public interface from the SwiftUI module:</p>
<pre><code class="prettyprint lang-swift">/// Represents a stored variable in a `View` type that is dynamically
/// updated from some external property of the view. These variables
/// will be given valid values immediately before `body()` is called.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol DynamicProperty {
/// Called immediately before the view's body() function is
/// executed, after updating the values of any dynamic properties
/// stored in `self`.
mutating func update()
}
</code></pre>
<p>As you can see, the current documentation is frustratingly sparse; even almost self-contradictory. One says that it is a stored variable that updates an external property of a view, and the other says that it represents a stored variable that is updated <em>from</em> some external property of the view. So what in the heck is a dynamic view property?</p>
<p>A dynamic property is a special type of property that stores its value <strong>indirectly</strong> in some interally managed memory, <em>separate</em> from the view’s memory. As you recall earlier in the article, we noted that SwiftUI views are simply models, and not actual the actual render tree. Dynamic view properties are what connect and describe the bridge between a <code class="prettyprint">View</code> and its render tree at runtime. </p>
<p>The storage of a dynamic view property is <strong>tracked</strong> by the framework’s runtime, and whenever it changes, the <code class="prettyprint">View</code>s dependent on it are recomputed and re-rendered as necessary. There is a lot of clever static and dynamic optimization that goes into making the re-rendering as efficient and conservative as possible.</p>
<p>The property wrapper feature recently accepted and implemented in Swift 5.1 is what makes them truly special. These structures have complex underlying mechanisms to interface with the SwiftUI runtime, but are accessible and usable in your <code class="prettyprint">View</code> structure’s code as if they are normal Swift properties!</p>
<p>If you’re familiar with <code class="prettyprint">Combine</code>or <code class="prettyprint">RxSwift</code>, a useful analogy might be to think of a dynamic view property as <code class="prettyprint">Publisher</code> or <code class="prettyprint">Observable</code>, that hides its internal implementation and reactive nature.</p>
<p>Below is a demonstration of the most commonly used dynamic view property type, <code class="prettyprint">@State</code>:</p>
<pre><code class="prettyprint lang-swift">struct ContentView {
@State var counter: Int = 0
var body: some View {
VStack {
Button(action: increment) {
Text("Increment")
}
Text("Count: \(counter)")
}
}
func increment() {
counter += 1
}
}
</code></pre>
<p>If you run the code above and set a breakpoint anywhere inside <code class="prettyprint">body</code>, you will see that it is triggered every time you press the “Increment” button. This is because everytime you tap it, your the <code class="prettyprint">increment()</code> function is called, mutating the <code class="prettyprint">counter</code> variable and triggering a re-render of <code class="prettyprint">ContentView</code>. </p>
<p>This re-render is necessary as because <code class="prettyprint">Text("Count: \(counter)")</code> is dependent on the dynamic view property <code class="prettyprint">counter</code>. The framework is intelligent enough to re-render only the counting text, and not the <code class="prettyprint">Button</code>. </p>
<p>This also brings us back to the first principle of data flow in SwiftUI:</p>
<blockquote class="short">
<p>Reading data creates dependencies.</p>
</blockquote>
<p>If you were to add another property (dynamic or not) the dependency would have to be <strong>declared</strong> in the view structure itself. It is not possible to defer the dependencies of the view, as it is possible with <code class="prettyprint">UIView</code> or <code class="prettyprint">NSView</code> in <code class="prettyprint">AppKit</code>, which expose a whole sleuth of mutable properties, which may be referenced and reassigned from any part of your code with a reference to the view. </p>
<p>This also highlights the <strong>functional</strong> aspect of SwiftUI, in that SwiftUI views are a function over their dependencies (as implemented in the <code class="prettyprint">body</code> getter).</p>
<p>While now we understand how data is passed <strong>down</strong> a SwiftUI view hierarchy, we still don’t know how to pass it <strong>up</strong>. This is where <code class="prettyprint">Binding</code> comes in.</p>
<h2 id="what-is-a-code-classprettyprintbindingcode_2">What is a <code class="prettyprint">@Binding</code>? <a class="head_anchor" href="#what-is-a-code-classprettyprintbindingcode_2">#</a>
</h2>
<p>Let us examine the documentation:</p>
<blockquote class="short">
<p>A manager for a value that provides a way to mutate it.</p>
</blockquote>
<p>And now let us look at the public interface from the SwiftUI module:</p>
<pre><code class="prettyprint lang-swift">/// A value and a means to mutate it.
@propertyWrapper public struct Binding<Value> {
/// Initializes from functions to read and write the value.
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void)
/// The value referenced by the binding. Assignments to the value
/// will be immediately visible on reading (assuming the binding
/// represents a mutable location), but the view changes they cause
/// may be processed asynchronously to the assignment.
public var value: Value { get nonmutating set }
}
</code></pre>
<h3 id="a-way-to-mutate-what_3">A way to mutate what? <a class="head_anchor" href="#a-way-to-mutate-what_3">#</a>
</h3>
<p>A <code class="prettyprint">Binding</code>, in its simplest form, is nothing more than a getter and a setter paired together. Note the following initializer:</p>
<pre><code class="prettyprint lang-swift"> /// Initializes from functions to read and write the value.
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void)
</code></pre>
<p>… and that it simply accepts two parameters. A <code class="prettyprint">get</code> closure, and a <code class="prettyprint">set</code> closure. <code class="prettyprint">get</code> returns a <code class="prettyprint">Value</code>, set accepts one. But where are we getting it from, and where are we setting it to?</p>
<p>Dynamic view properties, <strong>up</strong> the view hierarchy. </p>
<p>Let us take the example of a simple text field:</p>
<pre><code class="prettyprint lang-swift">struct ContentView {
@State var someText: String = ""
var body: some View {
TextField("Placeholder", text: $someText)
}
}
</code></pre>
<p>You’ve noticed that we’ve declared a dynamic property, <code class="prettyprint">text</code>, and are passing it down to <code class="prettyprint">TextField</code>. You’ve also noticed that we are passing it as <code class="prettyprint">$someText</code>, instead of <code class="prettyprint">someText</code>. What’s up with the dollar sign?</p>
<p>The dollar sign is an operator that converts any given SwiftUI dynamic property to a <code class="prettyprint">Binding</code>. </p>
<p>If we take a look at the initializer of <code class="prettyprint">TextField</code>:</p>
<pre><code class="prettyprint lang-swift"> public init(_ titleKey: LocalizedStringKey, text: Binding<String>, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {})
</code></pre>
<p>We see that it accepts a <code class="prettyprint">Binding</code> of a <code class="prettyprint">String</code>, expressed simply as <code class="prettyprint">Binding<String></code>. This is what allows the <code class="prettyprint">TextField</code> to pass user-input <strong>up</strong> the view hierarchy, through <code class="prettyprint">text.value</code> (where <code class="prettyprint">text: Binding<String></code>).</p>
<p>When you, the user, type into the <code class="prettyprint">TextField</code>, the state variable <code class="prettyprint">someText</code> is updated through the binding that you passed down to the text field. This triggers a re-render of your view, also causing <code class="prettyprint">TextField</code> to refresh the text in display. It is highly important to note that the update and re-render are sequential and not simultaneous (which would be disastrously confusing).</p>
<p>When <code class="prettyprint">someText</code> is updated, the SwiftUI runtime <strong>queues</strong> a request to re-render the portion of the view hierarchy dependent on <code class="prettyprint">someText</code>. When your screen refreshes (at a speed of 60Hz for iPhones and 120Hz for iPad Pros), it recomputes and re-renders the affected portion (in our case, just the <code class="prettyprint">TextField</code>).</p>
<p>It is also important to note here that dynamic view properties <strong>cannot</strong> be mutated inside the view’s <code class="prettyprint">body</code> property, as it will trigger a runtime exception. The functional aspect of SwiftUI has resurfaced again here: SwiftUI provides us with a runtime-enforced invariant that <code class="prettyprint">body</code> is guaranteed to be side-effect free (as far as dynamic view properties are concerned).</p>
<p>And finally, the second principle:</p>
<blockquote class="short">
<p>Every piece of data has a source of truth.</p>
</blockquote>
<p>What is “a source of truth”? It is nothing but the source of data that your views depend on.</p>
<p>The concept of source of truth is extremely useful in the context of complex views, where multiple views and/or subviews depend on a single source of data. In traditional UIKit or AppKit, if you had multiple views dependent on the same “truth”, an on/off switch for example, you would need to synchronize the changes from one of the views to apply across the rest, as each view would maintain its own internal state of being on/off. </p>
<p>SwiftUI makes it nigh impossible for synchronization errors, as it allows you to utilize powerful structures such as <code class="prettyprint">Binding</code> to pass a <em>reference</em> to a source of truth <strong>down</strong> the view hierarchy. This is also where the concept of ancestry and composition become vital. In SwiftUI, data changes flow <strong>top-down</strong> (that is, top to bottom), and re-renders occur <strong>bottom-up</strong>. This is not to say that a view down in the hierarchy cannot <em>trigger</em> a change in data at the top of the hierarchy, it’s just that the change will flow from top to bottom.</p>
<p>The second principle of data flow in SwiftUI is perhaps best represented by the table below:</p>
<table>
<thead>
<tr>
<th></th>
<th>Source of Truth</th>
<th>Derived Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Read only</strong></td>
<td>Constant</td>
<td>Property</td>
</tr>
<tr>
<td><strong>Read-write</strong></td>
<td>
<code class="prettyprint">@State</code>, <code class="prettyprint">@ObservedObject</code> etc.</td>
<td><code class="prettyprint">@Binding</code></td>
</tr>
</tbody>
</table>
<p>A <code class="prettyprint">Binding</code> may be derived from any dynamic property, and passed down the view hierarchy as a means to reference data without duplicating the source of it.</p>
tag:vmanot.com,2014:Post/for-antara2019-08-14T04:26:21-07:002019-08-14T04:26:21-07:00For Antara<p>The mellow embrace of blue,<br>
With a silent whisper of white,<br>
Dipped gently in lavender,<br>
Flowing fill into sight.</p>
<p>The quiet stretch of infinity,<br>
Peering deep into the soul,<br>
An ocean of serenity,<br>
Washing away the toll.</p>
<p>An impossible canvas beheld,<br>
Each stroke brushed past, <br>
Dark painted darker,<br>
A memory etched last.</p>
<p>Persuasive, pristine, perfect,<br>
A shapeless void in flight;<br>
That, my dear,<br>
Is the beauty of night.</p>
tag:vmanot.com,2014:Post/reimplementing-swiftui-s-deprecated-relative-view-sizing-functions2019-07-19T12:43:33-07:002019-07-19T12:43:33-07:00Reimplementing SwiftUI's deprecated relative view sizing functions.<p>With Xcode 11 beta 4, Apple deprecated SwiftUI’s <code class="prettyprint">View.relativeSize</code> function (as well as <code class="prettyprint">View.relativeWidth</code> and <code class="prettyprint">View.relativeHeight</code>). </p>
<blockquote class="short">
<p>The <code class="prettyprint">relativeWidth(_:)</code>, <code class="prettyprint">relativeHeight(_:)</code>, and <code class="prettyprint">relativeSize(width:height:)</code> modifiers are deprecated. Use other modifiers like <code class="prettyprint">frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)</code> instead. (51494692)</p>
</blockquote>
<p>For those dismayed by these changes, there’s an easy reimplementation available using <a href="https://developer.apple.com/documentation/swiftui/geometryreader"><code class="prettyprint">GeometryReader</code></a>:</p>
<pre><code class="prettyprint lang-swift">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 {
GeometryReader { geometry in
self.frame(
width: geometry.size.width * ratio,
alignment: alignment
)
}
}
public func relativeSize(
width widthRatio: CGFloat,
height heightRatio: CGFloat,
alignment: Alignment = .center
) -> some View {
GeometryReader { geometry in
self.frame(
width: geometry.size.width * widthRatio,
height: geometry.size.height * heightRatio,
alignment: alignment
)
}
}
}
</code></pre>
tag:vmanot.com,2014:Post/3d-touch2019-05-26T23:35:45-07:002019-05-26T23:35:45-07:003D Touch<p>3D Touch is a woefully underrated feature in today’s modern iPhones. There are now (what I consider to be) credible <a href="https://www.macrumors.com/2019/05/24/2020-iphones-acoustic-full-screen-touch-id-rumor/">reports</a> suggesting that Apple intends to drop this feature in their 2019 iPhone models.</p>
<p>This is highly unfortunate if true.</p>
<h2 id="what-is-3d-touch_2">What is 3D Touch? <a class="head_anchor" href="#what-is-3d-touch_2">#</a>
</h2><blockquote class="short">
<p>Ultimately, this is our focus. 3D Touch is something we’ve worked on for a long time—multi, multi, multi years</p>
</blockquote>
<p>3D Touch was introduced circa 2015 with the iPhone 6S. It’s the extra informational input of pressure with every touch on the screen. Apparently it was something they’d been working on <a href="https://www.bloomberg.com/features/2015-how-apple-built-3d-touch-iphone-6s/">for a while</a>. </p>
<h2 id="why-is-going-away_2">Why is going away? <a class="head_anchor" href="#why-is-going-away_2">#</a>
</h2>
<p>Simply put - it failed to become an idiomatic element of the iPhone’s UX language.</p>
<p>Many have speculated on why this is so. Here are the top 5 reasons that I have surmised:</p>
<ol>
<li>A lack of marketing.</li>
<li>Inconsistent availability across iOS.</li>
<li>Lack of any visual cues to enable discovery.</li>
<li>Lack of developer creativity, from both Apple and 3rd party developers.</li>
<li>It’s unnecessary as a feature, and Haptic Touch is good enough.</li>
</ol>
<p>I personally lean more towards 1-3, with 4 being a soft reason and 5 being absolutely untrue.</p>
<h2 id="haptic-touch_2">Haptic Touch <a class="head_anchor" href="#haptic-touch_2">#</a>
</h2>
<p>“Haptic Touch” is simply a long press gesture coupled with a haptic response. It is touted as the replacement for 3D Touch, and is implemented as such for the iPhone XR. Apple, as always, has chosen to parade it as if it is the greatest thing since sliced bread.</p>
<h2 id="why-should-i-care_2">Why should I care? <a class="head_anchor" href="#why-should-i-care_2">#</a>
</h2>
<p>Because Haptic Touch is simply not a replacement, and can never <em>be</em> a replacement for 3D Touch. It is a hacky attempt at emulating 3D Touch at best. </p>
<p>Haptic Touch requires you to long-press and <strong>wait</strong>. </p>
<p>3D Touch is <strong>instantaneous</strong>. </p>
<p>Haptic Touch over 3D Touch is clearly a degraded user experience. Do not let anyone trick you into believing otherwise, Apple most of all. </p>
<h2 id="amongst-other-things_2">Amongst other things: <a class="head_anchor" href="#amongst-other-things_2">#</a>
</h2><h3 id="on-inconsistent-availability-and-the-lack-of_3">On inconsistent availability and the lack of discoverability… <a class="head_anchor" href="#on-inconsistent-availability-and-the-lack-of_3">#</a>
</h3>
<p>One of the easiest ways for Apple to have made 3D Touch pervasive and consistently discoverable across the system, in my opinion, would’ve been to automatically convert every single long-press gesture into a 3D Touch gesture. It needn’t have supplanted long-press, but simply added to it. </p>
<p>This has a couple of benefits: </p>
<ol>
<li>Clear demonstration of utility - 3D Touch offers a faster route of access as compared to a long-press gesture. </li>
<li>Consistency - all apps immediately benefit from 3D Touch across all screens at once, instead of the developer having to manually reiterate over every control in their application(s).</li>
<li>Discoverability - users soon realize that long-press gestures could be activated via 3D Touch, and automatically adapt based on learnt knowledge of existing gestures rather than just trying to press hard on every UI element in the screen.</li>
</ol>
<h3 id="on-the-lack-of-developer-effort_3">On the lack of developer effort… <a class="head_anchor" href="#on-the-lack-of-developer-effort_3">#</a>
</h3>
<p>As a developer, Apple has not made it easy for me to implement a 3D Touch action. Instead of providing a canonical <code class="prettyprint">UIGestureRecognizer</code> subclass for 3D Touch (as they so easily <a href="https://krakendev.io/force-touch-recognizers/">could have</a>), they decided to leave it up to the developer to implement. </p>
<p>This makes something that could’ve been stupid simple to integrate annoying and effortful to support.</p>
<p>It’s not just 3rd party developers who suffer from this, it’s Apple too. The Messages app requires a painfully slow long-press to bring up the effects menu, and it could’ve easily been replaced/augmented by a 3D Touch recognizer.</p>
<h3 id="on-the-lack-of-creativity_3">On the lack of creativity… <a class="head_anchor" href="#on-the-lack-of-creativity_3">#</a>
</h3>
<p>Apple has clearly missed out on certain use cases for 3D Touch. Last year, I demonstrated two such cases and won a hackathon for doing so. You can find the code for the project <a href="https://github.com/vmanot/iTech2018">here</a>.</p>
<p>I took existing multi-touch gestures, such as rotate and zoom, and converted them to single-touch gestures with the help of 3D Touch - effectively expanding the scope of single-handed usage for apps implementing these operations.</p>
tag:vmanot.com,2014:Post/context-capturing-c-function-pointers-in-swift2019-02-13T10:56:36-08:002019-02-13T10:56:36-08:00Context capturing C function pointers in Swift.<p>Take the following code:</p>
<pre><code class="prettyprint lang-swift">func foo() {
let bar = NSObject()
let f: (@convention(c) () -> ()) = {
print(bar)
}
}
</code></pre>
<p>This will not compile. You will instead be presented with the following error:</p>
<pre><code class="prettyprint lang-swift">error: a C function pointer cannot be formed from a closure that captures context
</code></pre>
<p>While you are unlikely to ever encounter this error in typical iOS development, it may arise as the result of, say, an attempt to interface with a low-level C library/framework. In my case, I was trying to construct a parameter for a low-level POSIX function (<code class="prettyprint">pthread_create</code>), which only accepted a C function pointer. </p>
<p>There is a (dirty) workaround:</p>
<pre><code class="prettyprint lang-swift">import ObjectiveC
import Swift
func cFunction(_ block: (@escaping @convention(block) () -> ()))
-> (@convention(c) () -> ()) {
return unsafeBitCast(
imp_implementationWithBlock(block),
to: (@convention(c) () -> ()).self
)
}
</code></pre>
<p>This effectively allows you to write:</p>
<pre><code class="prettyprint lang-swift">func foo() {
let bar = NSObject()
let f: (@convention(c) () -> ()) = cFunction {
print(bar)
}
}
</code></pre>
<p>Which is, in fact, valid Swift code.</p>
<p>So… what does <code class="prettyprint">cFunction</code> do? It:</p>
<ul>
<li>Takes an Objective-C block pointer (specified using the attribute <code class="prettyprint">@convention(block)</code>).</li>
<li>Uses <a href="https://developer.apple.com/documentation/objectivec/1418587-imp_implementationwithblock"><code class="prettyprint">imp_implementationWithBlock</code></a> to construct a C function pointer from aforementioned block.</li>
<li>Uses <a href="https://developer.apple.com/documentation/swift/1641250-unsafebitcast"><code class="prettyprint">unsafeBitCast</code></a> to cast said function pointer to the appropriate Swift representation (another attributed function type, this time with <a href="https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_functions_in_swift"><code class="prettyprint">@convention(c)</code></a>)</li>
</ul>
<p>While this works, there are a few points to note: </p>
<ul>
<li>It relies on the Objective-C runtime, using a function that is typical reserved for converting C function pointers with arguments usually in the format of <code class="prettyprint">id, SEL, ...</code>. </li>
<li>In the example code, <code class="prettyprint">bar</code> will be retained indefinitely. That is because C function pointers are not deallocated like Objective-C block pointers once they go out of scope. You must manually deallocate <code class="prettyprint">bar</code> once you are done using it. This may be done by way of a flag, or based on some information derived from maybe an argument passed to the callback.</li>
</ul>