1. Sneak peek of something I’ve been working on this past couple of weeks.

    SwiftUI Directory

  2. Impressions from the Apple Event

    Some of my impressions from the Apple Event from last Tuesday:

    • The intro video was fun to watch, for once.
    • Tim skipped the numbers update this time around. Good riddance.
    • Apple Arcade is at least 4 years late. I’ll bite, regardless.
    • Apple TV+ is cheaper than I, and many others, had expected.
    • While I got used to the notch, I could get used to not having it. Too bad it’s here to stay another year, at least.
    • Hats off for showing the name of the photographers and artists when showcasing photos and videos.
    • “It’s so pro.”
    • Save for the Watch’s always-on feature, the event didn’t quite live up to its title, “By Innovation Only.”
  3. On Truncating Feed Content

    While skimming my RSS subscriptions this morning, I came across this tidbit from NetNewsWire:

    On the Many NetNewsWire Feature Requests to Show Full Web Pages

    […]

    There is a solution to the problem of showing full content and not leaving the app, and it’s a feature that really does belong in an RSS reader: using content extraction to grab the article from the original page.

    If you’ve ever used Safari’s Reader view, then you know what I’m talking about. The idea is that NetNewsWire would do something very much like the Reader view (but inline, in the article pane), that grabs the content and formats it nicely, without all the extra junk that is not the article you want to read.

    Let me be clear about this: Truncating content in RSS feeds is, without a sliver of doubt, an accessibility issue first and foremost. Accessibility as in making your content accessible to your readers wherever they chose to subscribe to your feeds—be it a mobile app, a command line, or through a screen reader. Undermining this aspect and coercing them to visit your website, no matter how much love you poured into it, is short-sighted at best, and inconsiderate at worst.

    I get that authors need to pay the bills, and some of them resort to sponsorships or ads to do so. But it’s user-hostile to presume that your subscribers don’t know any better and that they can only enjoy your content directly on your website.

    Authors who care about their readership have already figured out perfectly legitimate ways to monetize their feeds without any content truncation. Those who don’t are unlikely to bother and will continue to do a disservice to their readers.

    In the meantime, industrious developers will keep finding workarounds to restore functionality that users yearn for. And nothing can stop that, because open always wins.

  4. I’ve been running into several abstruse issues when smoke testing this website’s feeds in some RSS readers, including the newly released NetNewsWire 5. Upon further investigation, I found out that due to a glaring misuse of some Node.js APIs, all URLs have been missing a / after the https part1.

    The bad news? Once the fix is deployed, most RSS readers will reset the read status of the entire feed, since the individual entries are uniquely identified by their URLs. What’s worse, readers that cache previous entries will end up with duplicate content.

    I apologize for the inconvenience that this might cause and promise to be more careful to avoid syndication-related bugs like these in the future.


    1. For the curious, I inadvertently used the path.join(…) method instead of url.resolve(…) to construct these URLs. The former is only supposed to be used in the context of file system paths, not URLs.

  5. By default, git fetch gets an updated list of remote branches from the remote and sets up remote branch references locally. However, it doesn’t delete stale references that no longer have a counterpart on the remote. Trying to get rid of these using the git push -f origin:branch-name command will fail with a remote ref does not exist error.

    To delete stale remote references, you need to pass the --prune option to fetch like so:

    git fetch --prune
    - [deleted]  (none) -> origin/branch-name
  6. On Keeping SwiftUI DRY

    If we were to represent the hierarchy of our refactoring itches as a pyramid, eliminating duplication would be at the very bottom. The DRY principle, as it is often referred to, is the uncontested cornerstone of good development practices.

    SwiftUI, as new and unpolished as it is, already exposes some powerful APIs for that end. We’ve been using view extensions, view modifiers, and preference keys on a constantly growing codebase at work. If you’re looking to learn more about these largely undocumented capabilities, look no further than these two fresh posts:

  7. @kaishin onPreferenceChange() did not change 😉 It always required Equatable (how would it detect changes otherwise!). What did change though, is that Anchor no longer conforms to Equatable 😕

    — The SwiftUI Lab (@SwiftUILab) August 3, 2019

    I previously assumed that onPreferenceChange(_:perform:) added the Equatable requirement, but it turns out that Anchor<Value> dropped its Equatable conformance instead, as pointed out by @SwiftUILab and the official documentation.

    A curious change, regardless.

  8. Undocumented View Preference Changes in Beta 5

    Update: My assumption was wrong. Corrected here.

    I haven’t seen this mentioned anywhere, but the onPreferenceChange(_:perform:) view instance method now requires the preference key value type to conform to Equatabale as of Beta 5.

    In practice, this means that oPreferenceChange can no longer be used with preference keys that have an Anchor<Value> as their value type or a as a property of their value type, since Anchor itself doesn’t conform to Equatable. I fixed this by passing the GeometryProxy instance to a custom view modifier that unpacks the anchor first using the provided proxy, then passes the result as a CGFloat instead.

    For more on preference keys and anchors check out this informative blog post series.

  9. My Screen Time breakdown for last week. The time I used to spend on Twitter and Mastodon has shifted to reading, writing, and—ahem—browsing Reddit.

    Screen Time Summary

  10. Hello, world.

    Not long ago, I started toying with the idea of rolling out a custom-built microblog instead of relying on third party platforms. Today, I am happy to launch a modest first iteration.

    I will keep my single-user Mastodon instance and Twitter for the time being, but I will use them mainly to syndicate posts that will be published here first.