Michael Grant

SwiftUI class notes 2022-01-29

Screen Shot 2022-01-29 at 17.24.04.png
For now at least, weekends (and holidays) are the only times I really have the opportunity to focus on code for more than an hour or two at a time, so if I want to complete the more difficult “challenges” in 100 Days of SwiftUI or other courses, that’s when I’ll have to work on them. That means setting aside work on my own app(s) any time I reach a course challenge that I can’t get past in a couple of hours. Since (at least at my skill level, and maybe at all) there’s no reliable way of estimating how long it will take to reach a stopping point in my independent work, I can’t really do it the other way around. So I’m setting aside MinderBoard and turning back to 100 Days of Swift, which I’d like to finally finish within the next few weeks.

I’m actually focused on UIViewControllerRepresentable right now in both MinderBoard and the 100 Days challenge anyway.

Nick Sarno’s Use UIViewControllerRepresentable to convert UIKit controllers to SwiftUI video on YouTube and Paul Hudson’s series starting with Wrapping a UIViewController in a SwiftUI view cover very similar territory. Without digging through Apple’s documentation, the UIImagePickerController type in Nick’s video and the PHPickerViewController in Paul’s seem to do (exactly?) the same thing.

The code in the two tutorials is also very similar, with a few notable exceptions. Rather than replicating the view controller struct’s @Binding variables inside the Coordinator class, Paul creates a reference to the view controller as the Coordinator’s parent, allowing us to access its properties. This seems like a much more elegant approach. Using the view controller’s .dismiss() method also feels cleaner than passing showScreen around as a binding.

By defining the @State image variable in his main SwiftUI ContentView as an (optional) UIImage? rather than an (optional) SwiftUI Image? in the first place, on the other hand, Nick has no need of Paul’s additional @State inputImage variable, loadImage() function, and .onChange() modifier.

Paul’s beautiful dogs make an appearance in his videos, so that’s points for him. Advantage, Paul Hudson.


For Paul’s Challenge I do need to detect when a new photo is added, so I’ll actually still need the .onChange modifier. But it’s getting to be dinner time, so I’ll continue tomorrow.

Why do Markdown unordered lists in my micro.blog posts look fine in the Mac app preview but display as unbroken paragraphs in Safari?

SwiftUI class notes 2022-01-23

Still working on getting my head wrapped around UIViewRepresentable and UIViewControllerRepresentable. A pair of YouTube videos from Nick Sarno (Swiftful Thinking) is offers a helpful different perspective from Paul Hudson’s material that I’ve mostly been following.

Not sure I quite get the concept of “context”.

Elements of a UIViewRepresentable struct:

  • @Binding var — data being passed between the representable UIView and the parent SwiftUI view
  • Coordinator class and func makeCoordinator() -> Coordinator
  • func makeUIView(context: Context) -> some UIView
  • func updateUIView(_ uiView: UIViewType, context: Context)

Open questions:

  • ¿Does every UIView and UIViewController subclass have its own delegate protocol?
  • ¿What’s the self._text thing about?

Excellent explanation by @twostraws of using UIViewControllerRepresentable and Coordinator to incorporate UIKit elements into a SwiftUI app. A complex topic clearly laid out. www.hackingwithswift.com/books/ios…

SwiftUI class notes 2022-01-02

Just like it says in the title, Peter Friese’s Building a To-Do List App with SwiftUI, Combine, and Firebase calls for a dive into Combine, which I haven’t studied yet.

combine harvester Seems like something I’m going to have to learn sooner or later, though. Fortunately I bought Daniel Steinberg’s A Combine Kickstart on Black Friday.

The question now is whether I want to take a 500+ -page detour before making something, when the plan for weekend coding was supposed to be to get away from tutorials and see what I can do on my own. Since I’ll be pushing and pulling data from outside my app, I’ll presumably want to use some kind of async code, but maybe I should try the new Swift async/await first instead? In which case, given that I’m not interested in using Firebase for this project either, Friese’s project may end up not being all that useful.

I’m not getting very far with just the Apple developer documentation for EventKit, so let’s see what else is out there…

SwiftUI class notes 2021-12-12

Friese’s Task model:

enum TaskPriority {
  case high
  case medium
  case low
}

struct Task: Identifiable {
  var id: String = UUID().uuidString
  var title: String
  var priority: TaskPriority
  var completed: Bool
}

By contrast, Apple’s native EKReminder is a class that inherits from EKCalendarItem, which in turn inherits from EKObject. Its accessible properties:

  • EKReminderPriority (an enum with values none, high, medium, and low)
  • priority: Int
  • startDateComponents: DateComponents?
  • dueDateComponents: DateComponents?
  • isCompleted: Bool
  • completionDate: Date?

And accessible properties inherited from EKCalendarItem:

  • calendarItemIdentifier: String
  • calendarItemExternalIdentifier: String! — external identifier as provided by the calendar server
  • calendar: EKCalendar!
  • title: String!
  • location: String?
  • creationDate: Date?
  • lastModifiedDate: Date?
  • timeZone: TimeZone?
  • url: URL?
  • hasNotes: Bool
  • notes: String?
  • hasAttendees: Bool — so a reminder can have attendees?
  • attendees: [EKParticipant]?
  • hasAlarms: Bool
  • alarms: [EKAlarm]?
  • hasRecurrenceRules: Bool
  • recurrenceRules: [EKRecurrenceRule]?

The EKObject class’s properties, booleans hasChanges and isNew, relate to saving and restoring state.

¿Why two different priority properties?
¿Why simply completionDate and not completionDateComponents?

SwiftUI class notes 2021-12-05

Not following a tutorial today, just going to see if I can wrangle control of EventKit.

On weekends I’m trying to get away from tutorials per se, although at this point in my developer journey I’ll still be stealing adapting a lot of other people’s code. I’ll do my best to credit anyone whose code I cite here on the blog, and of course I’ll observe licenses when it comes to publishing anything.

I’m interested in working with EventKit, Apple’s framework for accessing calendar and reminders data. Specifically, I want to build an app that works with reminders. So far I haven’t found much any sample code online that uses EventKit in a SwiftUI environment; Apple’s Calendars and Reminders Programming Guide doesn’t even use Swift but rather Objective-C. (If he sees this @chrislowiec will be saying “I told you so!”)

I’m going to try starting with Peter Friese’s Building a To-Do List App with SwiftUI, Combine, and Firebase, which seeks to replicate the built-in iOS Reminders app, but instead of rolling a clone of the system’s underlying Reminders data store in Firebase I’ll be connecting to the original one. Once the basic create/delete/edit functionality is in place I have some ideas for different ways to view and manipulate tasks that I think could be useful for myself and others. Oh, and I’ll be writing mine for macOS and possibly iPadOS, because I think the iPhone screen is going to be too cramped for what I have in mind.

Since I’m going to be switching out bits and pieces derived from sample code from different sources, I’m making this as modular as I can, with a separate file for each view. Other than that, a #if statement for the .navigationBarTitle modifier that’s not available for macOS, and a few naming changes to make it easier to replace various elements of Friese’s code later, I haven’t yet written anything today that’s not taken directly from there, so there’s not much point in posting any of the code here.

Not sure if I’ll return to this before next weekend. Tomorrow I’m going to pick up where I left off in Paul Hudson’s 100 Days of SwiftUI.

Alternative Christmas movies for people who hate holiday sentimentality:

  1. OK, I’ll give you Die Hard!

  2. Bad Santa

  3. Eyes Wide Shut

  4. … other suggestions?

SwiftUI class notes 2021-12-02

macOS custom menu command

https://developer.apple.com/tutorials/swiftui/creating-a-macos-app

“The pattern for defining focused values resembles the pattern for definining new Environment values: Use a private key to read and write a custom property on the system-defined FocusedValues structure.”

“definining” lol

I am lost. Time to read the Swift language reference?

private struct SelectedLandmarkKey: FocusedValueKey {
    typealias Value = Binding<Landmark>
}

extension FocusedValues {
    var selectedLandmark: Binding<Landmark>? {
        get { self[SelectedLandmarkKey.self] }
        set { self[SelectedLandmarkKey.self] = newValue }
    }
}

FocusedValues is a struct type defined in the SwiftUI framework, a “collection of state exported by the focused view and its ancestors”.

So, within the app, ¿FocusedValues knows if a given Landmark is selected/has focus?

  • [ ] Find a thorough explanation of the <AngleBrackets> syntax

  • [ ] And ¿what the heck is self[SelectedLandmarkKey.self]?

  • [ ] Also find documentation for SwiftUI .tag(x) modifier

  • SelectedLandmarkKey is a struct that I just defined.

  • So SelectedLandmarkKey.self is… a reference to that struct type?

  • And, in the extension, the first self is a reference to (an instance of?) FocusedValues

  • [ ] But FocusedValues is a struct, not an array or a dictionary, so ¿how does the square brackets syntax work with structs?

SwiftUI class notes 2021-11-28

Apple tutorial: Interfacing with UIKit

Completely lost on this coordinator stuff.

import SwiftUI
import UIKit

struct PageViewController<Page: View>: UIViewControllerRepresentable {
    var pages: [Page]
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIViewController(context: Context) -> UIPageViewController {
        let pageViewController = UIPageViewController(
            transitionStyle: .scroll,
            navigationOrientation: .horizontal
        )
        pageViewController.dataSource = context.coordinator
        
        return pageViewController
    }
    
    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
        pageViewController.setViewControllers([context.coordinator.controllers[0]], direction: .forward, animated: true)
    }
    
    class Coordinator: NSObject, UIPageViewControllerDataSource {
        var parent: PageViewController
        var controllers = [UIViewController]()
        
        init(_ pageViewController: PageViewController) {
            parent = pageViewController
            controllers = parent.pages.map { UIHostingController(rootView: $0) }
        }
        
        func pageViewController(
                _ pageViewController: UIPageViewController,
                viewControllerBefore viewController: UIViewController
            ) -> UIViewController? {
            guard let index = controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index == 0 {
                return controllers.last
            }
            return controllers[index - 1]
        }
        
        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerAfter viewController: UIViewController
        ) -> UIViewController? {
            guard let index = controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index + 1 == controllers.count {
                return controllers.first
            }
            return controllers[index + 1]
        }
    }
}

What do y’all think: update MailSuite and stick with Mail.app for another year, or drop a few extra bucks and jump ship to @MailMateApp?

SwiftUI class notes 2021-11-25

Yes, even on Thanksgiving. (I suppose I should write something about how grateful I am to have the wherewithal to learn code, etc., and honestly I am, but I’m allergic to the orchestrated sentimentality that accompanies the fall and winter holidays.)


CaseIterable

/// A type that provides a collection of all of its values.
///
/// Types that conform to the `CaseIterable` protocol are typically
/// enumerations without associated values. When using a `CaseIterable` type,
/// you can access a collection of all of the type's cases by using the type's
/// `allCases` property.
///
/// The compiler can automatically provide an implementation of the
/// `CaseIterable` requirements for any enumeration without associated values
/// or `@available` attributes on its cases. The synthesized `allCases`
/// collection provides the cases in order of their declaration.

Dictionary of arrays

var categories: [String: [Landmark]] {
        Dictionary(
            grouping: landmarks,
            by: { $0.category.rawValue }
        )
    }

SwiftUI class notes 2021-11-24

Still in the Apple SwiftUI tutorial.

I don’t like that the tutorial is having me drag in downloaded view files rather than writing them myself. Even if the code consists of techniques that have already been covered, I’m not a grizzled veteran who’s been coding Swift everyday for years, and the reinforcement would have been useful. I mean, I guess I could retype it from the downloaded source files…

An experiment: blogging my "class notes" 2021-11-23

Should I track down the source of the “snag” or just go on with the tutorial? I don’t really see myself drawing a lot of paths in my own apps, and I haven’t coded since starting my new (non-technical, alas) job, so I’d like to get on with the stuff I’m more interested in mastering.

SwiftUI badge background view, but instead of a perfect hexagon there's a snag at the upper right

I started the Apple SwiftUI tutorial as a break from Paul Hudson’s brilliant 100 Days of SwiftUI because the former includes a macOS lesson… but it’s preceded by quite a bit of iOS-centric material, and I still haven’t gotten to the Mac stuff.

The accompanying text of the tutorial (not the code itself, of course), always uses the full word ‘structure’, never just ‘struct’.


¿OK, what does Hashable do again, precisely?

Other than manually disabling and later reenabling cross-posting, is there a way to post to micro.blog without cross-posting on a per-post basis?

Back to (micro-) blogging, in the spirit of Andy Matuschak’s concept of “Working with the garage door open”. Time will tell how long I stick with it this time around and how often I actually post.

Mission San Jose, San Antonio, 2020-12-25

Hi folks — I’m trying to decide whether I want to drop $300+ on an external Thunderbolt SSD. I’m driving a 2018 Mac mini with 500GB internal storage, and 1) I keep running into capacity issues, and 2) I’m a little leery of installing Big Sur on my work machine, even once the final release is available. So I’d like to get an external SSD that I can use as a boot drive, but I wasn’t aware until this morning how much more I’d have to pay for the Thunderbolt interface. Any thoughts?

Once again our Black sisters and brothers have shouldered the burden of saving this nation’s soul. That they have borne the brunt of the struggle again and again is itself one more in the long litany of injustices. But thanks to them we all are rediscovering our commitment to America’s highest ideals of freedom, justice, and equality. The struggle is far from over but the tides are turning.

Emergence

I’ve been thinking a lot about “emergence” lately, since with luck we’ll all be emerging from social isolation within a few more weeks and looking around at whatever’s left of our lives. I have a feeling there are a lot of aspects of our former ways of working and living that we won’t be able to go back to, any many others that we won’t want to. Our “business as usual” was already failing in increasingly obvious ways, and this forced reset is one of those crises that we can’t afford to let go to waste. Those of us fortunate enough not to be dealing with actual medical emergencies have an opportunity now to make choices that could shape not just our personal lives, but our whole societies for generations. So… currently mulling ideas for at least a major blog post on that theme, and beyond that we’ll see what emerges. I’d love to hear any thoughts y’all might have along these lines.

My sister in Germany just sent this:

What are we building after the plague? Because the world is never going back to “normal”. It’ll be up to us to create a world where the disasters of the early 21st century don’t just keep happening.

Zettelkasten

A Zettel is a slip of paper; a Zettelkasten is a “slip box”. Since that phrase doesn’t mean much in English, the German word is often used in English among #Zettelkasten method adherents. Niklas Luhmann’s Zettelkasten resembled a pre-digital-age library card catalog. The actual slips were roughly the size of index cards but on thinner stock. Modern zettelizers most often use digital files in a text management software application.

US distillers have been hard-hit by EU tariffs, but other high-growth export markets remain. Learn more #WhiskeyWednesday

Swift Passage is offering free assistance with 2020 State Trade Expansion Program (STEP) grant applications for eligible TX businesses. Reimbursement for up to $10K in export-related expenses. swift-passage-trading.com/2020/01/2…