Animating along a SwiftUI Path

We can use trigonometry and finite differences to animate rigid objects along a SwiftUI path.

The SwiftUI Path class is missing several useful methods for evaluating properties of a path:

  • finding the position (as a CGPoint) of a given fractional position of the path.
  • finding the heading (as an angle) of a given fractional position of the path.
  • finding the total length of the path, measured in points.

Happily, we can write these methods based on the existing trimmedPath method.

With the aid of these methods it’s possible to create animations that move rigid bodies along arbitrary paths.

More …

The Zen of Advent of Code

For the past three years I’ve been participating in the Advent of Code programming puzzle contest. It’s a free contest that has run every December since 2015. It’s appropriate for people who can write programs at the undergraduate college student level. (Which means that many high school students can do it.)

The way the contest works is that, starting at midnight East Coast time on the morning of December 1st, a puzzle is announced every day from December 1st to December 25th.

The puzzles are designed to be solved by an ordinary developer within a few hours. The focus tends to be on figuring out a good algorithm, and the problems are usually solvable using under a hundred lines of code in standard Python.

More …

Why Apple is Unlikely to Create a Game Console

Apple’s new M1 Max SOC has good graphics performance. Some people are speculating that this would enable Apple to create a competitive video game console. I think that’s unlikely.

The bull case for Apple making a video game console is:

  • Apple has designed a series of excellent SOCs to serve their existing product lines.
  • The recent Macbook Pro M1 Max SOC has performance that is comparable to AMD/NVIDIA laptop gaming SOCs, but at lower power consumption.
  • Apple could use the M1 Max SOC to create a video game console with similar performance to existing video game consoles, but with much lower power requirements.
  • This would enable Apple to compete in the console video game market.

The bear case is:

  • Apple doesn’t care about the console video game market. It’s small and not growing.
  • Video game console customers don’t value the benefits that Apple’s M1 Max SOC would bring to video games.

In this blog post I explain why the video game console market is shaped the way it is.

More …

A Smooth AsyncImage Replacement

iOS 15.0 introduced an AsyncImage SwiftUI view to enable asynchronously loading URL-based images. AsyncImage works well for many scenarios, but has several limitations:

  1. AsyncImage doesn’t provide a mechanism for “inflating” an image before drawing it. This means that large images can take a long time to render the first time that they are drawn. This can cause “hitches” or “jank” when scrolling.

  2. AsyncImage doesn’t provide a mechanism for pre-scaling large UIImages down to screen size. This can cause slow rendering and excessive memory use when displaying large images.

Here’s a replacement view, SmoothAsyncImage, that fixes these two problems.

More …

Swift 5.5 Concurrency

Introduction

Concurrency features are now available in Swift 5.5, released as part of Apple Xcode 13 beta 1. Let’s update our Web Scraping code to use the Swift 5.5 concurrency APIs.

More …

Web Scraping Using Structured Concurrency

Introduction

In this tutorial we’ll modify our toy web scraper to use the newly proposed Swift async/await and Structured Concurrency APIs.

func scrapeHouseplants(url: URL) async throws -> HouseplantCategoryDictionary {
  return try reduceHouseplantInfos(
    infos: await scrapeListOfHouseplants(url: url, html: fetch(url: url))
      .asyncMap { ticket in
        (ticket.key, try scrapeHouseplantInfo(url: ticket.url,
                                              html:await fetch(url: ticket.url)))
      }
  )
}
More …

Speeding up Web Scraping

Introduction

In this tutorial we’ll use a variety of techniques to speed up our toy web scraper.

Program Version Time (s)
Original 17.7
Release mode 4.7
DispatchQueue.concurrentPerform 1.1
URLSession 0.6
More …

Web Scraping with SwiftSoup

Introduction

In this tutorial we’ll use the open-source Swift Soup library to scrape open-source houseplant data from the Wikipedia houseplants page.

Our program will scrape this URL: https://en.wikipedia.org/wiki/Houseplant

Our program will produce a JSON object containing the scraped data. It will look something like this:

{
    "Tropical and subtropical": {
        "Aglaonema" : {
            "description": "These are evergreen perennial herbs with stems…'
        }
        …
    }
    …
}
More …

Advent of Code 2020

My college freshman son and I competed in this year’s Advent of Code coding competition. It was a battle of youthful energy against wisdom & experience. I am somewhat chastened to report that we scored about the same.😅

My son used Python, and didn’t even use any of the fancier Python libraries or language techniques. He also eschewed the debugger, doing all his debugging using print() statements.

I used Swift & Xcode, and tended to use every feature of the language and libraries.

That we scored similarly probably shows that the two languages are evenly matched for the kinds of problems that were given in this contest.

The Advent of Code puzzles typically come in two parts: The first part is usually easier, the second part usually adds a twist that requires extending the original solution.

In looking back on the month, I think that, compared to my son, I typically over-engineered my solutions. I introduced enums and structs and helper functions where he used the built-in data types and copy-and-paste. This usually gave him a signficant edge on the time to solve the first, “easier” problem.

My over-engineering sometimes paid off. I usually had easier debugging (due to more typechecking), and sometimes it was easier to refactor my code for the “twist” in problem two. Plus occasionally having a compiled language helped. Althoght not that often. The AoC problems are designed to be solvable in short run times in Python, even on old hardware.

My edge, the reason that I was competitive, was that I have enough experience that I could usually figure out how to solve a given problem. In later days of the contest, when the problems got harder, I felt that this was an unfair advantage, so I would give my son a hint about what web searches to use to figure out a good way of approaching the problem.

Overall we had fun. Shout out to the excellent r/adventofcode subreddit. Each day, after we solved the puzzles ourselves, we would check in with the subreddit to see other solutions.

Improving my Swift skills

Using Swift to compete in AOC has encouraged me to explore parts of Swift that I hadn’t had a need to or chance to learn before.

  • String processing, and the relationship between String, Substring, and Character.
  • Regular expressions
  • map, reduce, filter, forEach, compactMap and occasionaly flatMap.
  • Classic Algorithms
  • SIMD for points.
  • typealias for briefer code.
  • Generics for reusable algorithms.
  • NSCountedSet
  • ArraySlice and the various Ranges.
  • Creating Sets and Dictionaries the functional way rather than imperatively.
  • Identifiable, RawRepresentable, Hashable, CaseIterable, CustomStringConvertible.
  • Sorting
  • Using value types as much as possible.

Room for Improvement

Swift is a good language for coding contests. Certainly much less verbose than many other Java-like languages. However, there are still some speed-bumps compared to Python or F#.

  • String processing is verbose.
  • Regular expressions are very verbose.
  • No automated synthesis of Comparable.
  • Tuples can’t conform to Hashable, limiting their use as a general value type.
  • The Swift standard library is missing many useful algorithms and collection classes.
    • These can be added via third party libraries, but that takes time during a contest.
  • The tradeoff between debug builds and release builds.
    • Debug builds are slow.
    • Release builds are difficult to debug.

Previous AoC contests

The old Advent of Code contests are all still “live”. You can’t get a timed score, but you can still enter and complete any contest.

I first did Advent of Code last year, but this year in addition to entering the 2020 contest I also completed all the earlier years’ contests. r/adventofcode was a handy resource for this task. There are archived posts for discussing the solutions to each day’s puzzles for every year’s contest.

Blogging from an iPad

After a day’s hacking, I am pleased that I can update my github.io-based blog using an iPad. Here’s how I did it:

  1. I researched the topic, finding some good info on Avery Vine’s post.

  2. I wrote a script, ConvertBlogFromPublishToJekyll.swift, to convert my posts from the markdown flavor used by Publish to the markdown flavor used by Jekyll.

That’s it, there’s no step three. Whenever I want to post to my blog from my iPad, I just edit the sources in Working Copy. Because the blog is backed by a git project, I can also edit the blog from any other device that supports a git client, including a regular Mac or PC.

This works because Jekyll support is built into github.io web pages. Whenever a new commit is made, Github’s servers automatically run the Jekyll app to regenerate my blog.

Pro tip: The Working Copy text editor can be switched from “Programming” mode to “Natural” mode. Natural mode provides spell checking.