Hi, I'm Alex Pretzlav

I write apps for humans, love to cook, and tinker with electronics. I live in Oakland, CA.

My Everyday Yogurt Recipe

17 January 2024

Our family goes through a lot of yogurt. Early on in the pandemic we were going through 64 ounces of Straus Yogurt a week, which was expensive and hard to keep stocked when we felt unsafe going to the grocery store.

Enter the Instant Pot.

I knew that theoretically one could make yogurt in the instant pot. Now I know it’s incredibly easy! It’s much cheaper and less wasteful than buying gallons of premium yogurt from Berkeley Bowl. So here’s what I do to make a half gallon of yogurt most weeks:

two quart-size glass jars filled with white fluid

Instant Pot Yogurt

Total Time: 11.5 Hours

Ingredients

  • ½ gallon whole milk (I use Clover Organic)
  • 2 tb yogurt (store bought or homemade with an heirloom culture) see note

Equipment

Instant Pot, whisk, instant-read thermometer, glass jars or another container that can hold two quarts of yogurt.

Recipe

Start this either first thing in the morning or before going to bed at night.

  1. Put the milk in the instant pot. If you’re pouring from a 1 gallon jug, I pour to about 2mm below the 2 qt line so the resulting yogurt will fit nicely in two glass quart mason jars.
  2. Close and lock the lid.
  3. Set the instant pot to Yogurt: Pasteurize. The instant pot will warm and then hold the milk at 180°F for 3 minutes. This is how my “Duo Evo Plus” looks, yours may be different:
    the lit up LCD display of an instant pot, the Yogurt button is illuminated, and the display shows "0:03 Pasteurize"
  4. When the instant pot beeps that it’s finished, pull out the inner pot and set it out to cool at room temperature. 1
  5. Wait for the milk to reach 115° - 110° F. If it goes below 110°, reheat it on a very low stove burner. During this time a small skin may form on the milk. I usually skim it off with a fork and throw it in the compost.
  6. Pour a small amount of the pasteurized milk into a bowl and mix with the 2 tb yogurt.
  7. Pour the milk-yogurt mixture back in the pot.
  8. Put the liner pot back in the Instant Pot and seal the lid.
  9. Set the Instant Pot to Yogurt, Ferment mode at “high” for 11 hours.
  10. Go to bed or work.
  11. When the instant pot beeps to signal it’s done, open the lid carefully, as a lot of condensation will have collected on the inside of the lid.
  12. Vigorously stir the yogurt with a whisk until the curds are well incorporated and it has a smooth creamy texture.
    top down view of a stainless steel pot filled with white yogurt, a whisk is partially submerged in it
  13. Pour in to jars and refrigerate for 12-24 hours before eating. It should thicken to batter-like consistency, but it will never completely hold its shape.

On Culture

Store-bought yogurt works as a starter for this recipe, but it will only last a few generations. The cultures used in mass-market yogurt are carefully balanced to meet specific nutrition targets, but are not typically self-sustaining. If you want to keep making yogurt again and again, you can either get some heirloom yogurt from a friend to use as starter, or buy some online. I got some from a neighbor on our local Buy Nothing group.

  1. This process can be sped up by putting the pot in a bath of ice water, but the temperature will drop very quickly. If you do this, watch the temperature closely so it doesn’t get too cold. 


Swift Asset Code Generators

29 January 2016

Programmers generally agree that using “stringly-typed” data is a recipe for pain, but vanilla iOS development requires a lot of exactly that: image names, localized strings, storyboard and segue identifiers, etc. Following in the footsteps of great projects like mogenerator, now there’s a healthy selection of libraries that provide type-safe and IDE-friendly references to assets.

I tried out four popular projects which support Storyboards and Segues, plus these other features: 1

Library Type Safe(ish) Images Localized Strings Colors Reuse Identifiers Fonts
SwiftGen
Natalie
R.swift
objc-codegenutils

When I say type safe, I’m specifically referring to storyboard segues: since segues with identifiers are tied to a specific view controller, it’s possible to ensure the segue references are associated with the storyboard or view controller they are part of and push runtime crashes to become compiler crashes.

To test out these tools, I decided to convert the default Xcode Master-Detail Application template (plus a little extra) to use each of them and try it out.

I’ve put them all in to a github project you can check out if you want to see the code in action.

The Normal Way

There are two main Storyboard actions where I often use string based identifiers: performSegue and prepareForSegue. Here’s a typical example of presenting a view controller showing an image:

@IBAction func someButtonPressed(sender: AnyObject) {
    performSegueWithIdentifier("ImageView", sender: self)
}

and

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    switch segue.identifier {
    case "ImageView"?:
        if let dest = segue.destinationViewController as? ImageViewController {
            dest.imageToShow = UIImage(named: "lolwut")
        }
    default:
        break
    }
}

There are several things I don’t like about this approach. First, the segue identifier "ImageView" is a string. If the identifier changes in the storyboard, the code will crash at runtime. If the segue is moved to a different view controller, runtime crash. Code copied and pasted somewhere else? Runtime crash.

That default: break in the switch is annoying too. There’s a fixed set of segues defined on this view controller in the storyboard, and the compiler should know which ones those are.

SwiftGen

I started with SwiftGen, as it looked like it would have the best combination of features and type-safety I was looking for.

Here’s performSegue using SwiftGen’s generated identifier enum:

@IBAction func swiftGenButtonPressed(sender: AnyObject) {
    performSegue(StoryboardSegue.Main.ImageView)
}

The Main there is the name of the storyboard file where the segue is defined.

and prepareForSegue:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    switch StoryboardSegue.Main(rawValue: segue.identifier!) {
    case .ImageView?:
        if let dest = segue.destinationViewController as? ImageViewController {
            // This is a SwiftGen image asset reference
            dest.imageToShow = UIImage(asset: .Lolwut)
        }
    default:
        break
    }
}

There are a few things to note here that stand out to me. First, I have to force unwrap segue.identifier, even though Main(rawValue:) returns an optional. A helper initializer could have avoided that wart.

The main thing bugging me is the default: entry in the switch statement. It turns out SwiftGen lumps the segues in each storyboard file in to one enum. Since there will usually be different segues on different view controllers in one storyboard, a default: case will pretty much always be needed, which loses a lot of the compile time help enums are supposed to provide.

Natalie

@IBAction func natalieButtonPressed(sender: AnyObject) {
    performSegue(Segue.ImageView)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    guard let segueType: Segue = segue.selection() else { return }
    switch segueType {
    case .ImageView:
        if let dest = segue.destinationViewController as? ImageViewController {
            dest.imageToShow = UIImage(named: "lolwut")
        }
    }
}

Now this is getting somewhere. Segue is an enum defined as an internal class on the current view controller, so only segues this view controller supports are present. That means if I change the class of the view controller in the storyboard, this code will rightfully break. Also, Xcode’s code completion only offers me segues defined on this view controller in the storyboard. No default: clause is needed on the switch for the same reason. There’s a guard here because segue.selection() returns an optional, but that seems a small price to pay for the compiler knowing about the possible segues.

R.swift

At first R.swift didn’t look like it had as strong type support as the other two. It has just about the same number of stars on github as SwiftGen and I liked using the R system when I did Android development, so I gave it a shot.

@IBAction func rButtonPressed(sender: AnyObject) {
    performSegueWithIdentifier(R.segue.detailViewController.imageView, sender: self)
}

This is pretty clever. Even though I could call this segue from any view controller, if I move or rename the segue in the storyboard, the compiler will catch it. If I copy and paste this code to a different view controller class, though, it’ll crash at runtime.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let segueInfo = R.segue.detailViewController.imageView(segue: segue) {
        // This is how R references image assets
        segueInfo.destinationViewController.imageToShow = R.image.lolwut()
    }
}

R.swift takes a different approach to UIStoryboardSegue: it generates structs instead of enums. R.segue.detailViewController.imageView2 smartly returns an optional struct which if present contains correctly typed view controller references. This avoids that annoying cast in all the other examples!

R.swift gives an interesting tradeoff: while it doesn’t provide compiler-checked enum cases, it gives other ways to improve interaction with the type system and avoid unsafe casts.

objc-codegenutils

For completeness sake, I wanted to look at a popular non-Swift code generation library. Square’s objc-codegenutils looked well supported, even though it hasn’t been touched in two years.

@IBAction func codeGenUtilsButtonPressed(sender: AnyObject) {
    performSegueWithIdentifier(MainStoryboardImageViewIdentifier, sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    switch segue.identifier {
    case MainStoryboardImageViewIdentifier?:
        if let dest = segue.destinationViewController as? ImageViewController {
            dest.imageToShow = AssetsCatalog.lolwutImage()
        }
    default:
        break
    }
}

OK, it really doesn’t give you that much. If you look at the files it generates you can see how minimal it is. This is an acceptable improvement for an obj-c project, but in Swift I want something better.

Which which which?

I want a hybrid of Natalie and R.swift: I love the Segue inner enum Natalie uses to avoid repetitive boilerplate, but I really like the TypedStoryboardSegueInfo struct that R.swift constructs from a UIStoryboardSegue. It’s also worth pointing out that SwiftGen allows you to choose which types of assets you want to generate code for, so it’s perfectly reasonable to use a combination of libraries for different asset types.

I think for now I’m going to give Natalie a shot on a few projects and see how it goes. If I really miss the typed segue features of R.swift, maybe I’ll submit a pull request.

  1. I’ve left the popular Shark library off of this list because it only handles images, which are also handled by most of these libraries. 

  2. imageView is generated from the segue identifier: ImageView 


My Markdown Resume

06 November 2015

Since graduating college, I’ve maintained my resume in Markdown. I wanted an HTML version of my resume to put online, but I also wanted a readable text version. Markdown is perfect for readable text that generates simple HTML. Then, it’s easy to generate a good looking PDF from HTML.

There are plenty of other Markdown resume tools out there, but I’ve been using this since 2009 so I’m sticking with it. I’ve decided to finally extract it into a standalone tool and put it online. Here it is on github, with a basic README. Here’s an example resume.

Some features:

  • It uses MultiMarkdown, which supports many useful Markdown extensions
  • There’s a Makefile for generating HTML and PDF output and scp’ing to a host
  • There’s a little bit of CSS magic for making the PDF look nicer
    • In particular, it will append “: $URL” to any links not configured with a “link” class, so link URLs appear in print
  • It generates PDF via wkhtmltopdf. You’ll need to install it before PDF generation will work.
  • It’s easy to use as a submodule of an external git repository, so you can keep your resume private (I do).
  • That’s about it

Next Thing

07 March 2015

wires header


Friday was my last day at Silvercar.

In the last year I’ve built a prototype for a product1 that I’m really excited about. I’ve come to realize that if I want to make this real, I need to devote more than just spare cycles to it. Not only do I need more time to polish what I’ve made, but I need to figure how to build a real product, from funding to manufacturing. That process begins today.2

It’s been a little over two years since I took over as the only iOS engineer at Silvercar. I was terrified when I started. I had only ever worked with teams of experienced engineers and product leaders to build shipping apps. Now it was just going to be me. I grew in to the role and came to deeply appreciate the freedom and autonomy I had. I learned a hell of a lot from the rest of the team and from myself. I learned to take personal responsibility for my work and to challenge myself and grow as an engineer without having someone looking over my shoulder. I also learned about teaching, as I helped a teammate learn iOS over the last six months. I know I have a lot of improvement yet in that regard.

Now I’m ready for more freedom and autonomy.

I will be consulting for Silvercar on a limited basis as they continue to onboard new people. My intention is to build a small amount of consulting in to my weekly or monthly schedule to keep rent paid etc. If you’ve got a well-defined time-limited iOS project that needs doing, let’s talk.

  1. hint 

  2. OK, so I’m probably going to take a week and be a bum, then then we’re going to New York, then SXSW, so it’s more like that process begins next month. 


One of the features of Swift 1.2 I find most exciting is the addition of the @noescape attribute for block parameters:1

A new “@noescape” attribute may be used on closure parameters to functions. This indicates that the parameter is only ever called (or passed as an @noescape parameter in a call), which means that it cannot outlive the lifetime of the call. This enables some minor performance optimizations, but more importantly disables the “self.” requirement in closure arguments.

One of the places where the self. block requirement most frequently bothers me is in calls to UIView.animateWithDuration:

UIView.animateWithDuration(0.5, animations: {
    self.view1.frame.size.width += 200
    self.view2.frame.origin.x = self.view1.frame.maxX + 20
})

You can see in the debugger that the animations block passed to animateWithDuration is always executed synchronously, so it should be compatible with @noescape, but I’m not holding my breath waiting for Apple to add it.

I decided that instead, I would take a look at what it would take to implement my own animateWithDuration, method, using default parameters instead of the three method variations defined on UIView), and making the animations block noescape. completion can’t be noescape as it is called asynchronously when the animation completes.

Target Function

Let’s start with how I think my method definition should look:

public func animateViews(
    duration duration: NSTimeInterval,
    delay: NSTimeInterval = 0,
    options: UIViewAnimationOptions = .allZeros,
    @noescape animations: () -> Void,
    completion: (Bool -> Void)? = nil) {

A call to this looks a lot like the built-in methods, but the optional parameters allow some flexibility:

animateViews(duration: 1.2, delay: 0.2,
    animations: { view1.frame.origin.x += 50 },
    completion: { self.animationDidComplete($0) }
)

I’m going to build my version on top of the old-style UIView beginAnimations and commitAnimations class methods. These were the standard way to do UIView animations in the days before blocks. They provide almost the same functionality as the block-based methods but with more verbose syntax.

The normal way they are used is like so:

UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.2)

view1.frame.origin.x += 50

UIView.commitAnimations()

Our goal is to write a method that calls the right set-up functions for the animation parameters, calls the animations() block, then commits the animations. Additionally, we will ensure the completion block gets called when the animation completes.

Let’s ignore the completion block for now and focus on setting up the basic animation:

public func animateViews(
    duration duration: NSTimeInterval,
    delay: NSTimeInterval = 0,
    curve: UIViewAnimationCurve? = nil,
    @noescape animations: () -> Void {

    UIView.beginAnimations(nil, context: nil)

    UIView.setAnimationDuration(duration)
    UIView.setAnimationDelay(delay)
    if let curve = curve {
        UIView.setAnimationCurve(curve)
    }
    
    animations()
    
    UIView.commitAnimations()
}

I decided to only support animation curves rather than all of UIViewAnimationOptions. Most UIViewAnimationOptions can be implemented via UIView calls, but I find I very rarely use them.

The Completion Block

The old animation methods only support delegates, as they predate blocks completely. Not just that, but they support delegates in a very weird way: rather than defining a protocol, you provide a reference to any object, and then declare what selector on that object to call when the animation starts or ends. I need a small wrapper class to act as the delegate and call through to the provided completion block. I’ll call it AnimationDelegate, and to begin with, I need a static Set<AnimationDelegate>, as the animation does not retain its delegate. I’ll insert a delegate in the set when beginning an animation, and remove it when the animation completes and completion has been called:

private var delegates = Set<AnimationDelegate>()
final class AnimationDelegate: NSObject {
    let callback: Bool -> Void
    init(callback: Bool -> Void) {
        self.callback = callback
    }

then implement the standard signature for the animation completion delegate callback:

    func animationDidStop(
        animationId: String?, 
        finished: NSNumber, 
        context: UnsafeMutablePointer<Void>) {

        self.callback(finished.boolValue)
        delegates.remove(self)
    }
}

Finally, I need to instantiate an AnimationDelegate whenever a completion block is provided to animateViews, and add it to the delegates Set:

public func animateViews(
    duration duration: NSTimeInterval,
    delay: NSTimeInterval = 0,
    curve: UIViewAnimationCurve? = nil,
    @noescape animations: () -> Void,
    completion: (Bool -> Void)? = nil) {
        
        UIView.beginAnimations(nil, context: nil)
        
        if let completion = completion {
            let wrapper = AnimationDelegate(callback: completion)
            delegates.insert(wrapper)
            UIView.setAnimationDelegate(wrapper)
            UIView.setAnimationDidStopSelector("animationDidStop:finished:context:")
        }
        ...

I originally tried to use the context parameter to reference the block itself and avoid a wrapper class, but I couldn’t figure out how to get an UnsafeMutablePointer<Void> from a Swift block, and wasn’t sure I could trust the memory semantics with block copying even if I could.

So there you have it, UIView animation with default parameters and a @noescape animations block!

You can see the full example project on github.

  1. Requires apple developer account login. 


I’ve never been much of a blogger. I’ve had aspirations to start blogging many times, but never properly followed through. I’ve decided this time is going to be different.

I’m taking control of my own blog, on my own site, and making it as easy as possible to write. That means markdown, dropbox 1, and one a line command to update. I’ve done a great job so far spending three weeks of sporadic free time messing with setup instead of writing anything.

Over the years I’ve used livejournal, tumblr, wordpress, facebook, and twitter as “blogging” outlets, but never felt satisfied with any of them.

My first personal programming project ever, in 2007, was an attempt to build a blogging engine in Ruby on Rails that imported posts from livejournal, links from del.icio.us, and photos from flickr. It never really worked, certainly not well enough for me to direct anyone to it. It was far too ambitious for someone who barely knew how to program2.

Since then I kept thinking I should blog on a “real” site like wordpress.com, but only one person ever found my handful of posts. It was also a monumental task to get images, code, and notes organized to put into wordpress’ formatting engine. It wasn’t fun, so I never did it.

I’ve got a handful of technical things I want to talk about now (Swift!), and realized I need a single clear place to go when I do want to write something.

Nerd Stuff:

I set up a skeleton of a blog ages ago using Jekyll Bootstrap3, but never touched it after the initial setup. I used it to stage two paltry posts I put on wordpress after taking a stab at a game jam with friend Lily Cheng.

I looked into a handful of static blog engines4, but finally decided Jekyll did enough, but was small enough, that I would stick with it. The first order of business was to convert to bootstrap 3. I write mobile apps, priority 1 is my blog needs to be responsive. After a couple days of fiddling with bootstrap overrides and updating jekyllbootstrap’s layouts for bootstrap 3, I’ve got something I’m happy with for now.

TODO: make a sample Jekyll config using Boostrap 3’s sass files for easy overriding, like this. Also, autoprefixer, which both bootstrap-sass and bigfoot require. Unfortunately this doesn’t work with github pages.

I should also mention the tiny Makefile I wrote to simplify serving and uploading with some small config tweaks.

  1. and footnotes 

  2. Let alone understood asynchronous web processes, multiple APIs, and the difference between rails Controllers and tasks. 

  3. now defunct 

  4. Pelican and Hugo mainly, although I also considered writing something myself. Then decided not to. 


A week ago I sat down in front of The Wirecutter to try to buy a receiver. Here’s their pick for best of breed receiver:

Sony STR-DN840
The Sony STR-DN840

It’s SIX INCHES TALL. It’s not horifically ugly, but it sure isn’t pretty. It has every feature you can possibly imagine. When I went looking for something smaller, I found one company, Marantz, makes smaller a/v receivers, and they’re not even that small:

Marantz NR1403

Marantz NR1403

I really don’t have that many requirements. I don’t care about surround sound at all. A pair of good stereo loudspeakers will do better than surrounding yourself with cheap ones. Here’s what I want: a bunch of HDMI inputs, some stereo inputs, and an amplifier for two speakers. A remote control. I already have an Apple TV, but I’d love it if it turned on when I tried to play music.

So then I went looking for something simpler. An amplifier with a couple digital and a couple analog inputs. Hey, this looks pretty cool!

NAD D 3020

NAD D 3020

Except it’s $500. It doesn’t have any HDMI inputs (it targets audiophiles), so I’d still have to deal with this crappy switch that needs line of sight to a remote, because my TV doesn’t have enough plugs.

Then I remembered I had heard people talking about this new breed of cheap automotive receivers with surprisingly good sound quality for around $20.

image

Lepai LP-2020A+

But there’s no remote control at all. Kind of important for your TV sound. So then I started thinking.

image

Except it would suck. Enormously. No remote volume control, three power supplies, a pile of crap on my entertainment console.

But Wait

image

What if you threw in a Raspberry Pi and some cheap hardware bits? There’s a whole distro for hi-fi audio through a Raspberry Pi. It supports Airplay out of the box. It plays video too!. There’s an infrared remote kit for it for $7. I could throw together a mobile app in a weekend. I bet you could sell a lot of these for $300. I bet you could even make it modular. Want more analog inputs? Buy some more analog inputs. Plug them in.

Why isn’t anyone making this? c|net is already decrying the current generation of receivers. Sounds like I’ve got a project to start.


As feared expected, getting our game done in time for a deadline of January 23rd took precedence over writing about all the problems I ran into while making it. However, I’m still going to write about the experience here because I feel keeping a record of my journey of discovery will help and inspire future generations of would-be game creators who already know how to program.

When I last left off, I had a cursor on screen, and a pandacat at a fixed location. My next step was to get the pandas to move. Since we knew a central part of gameplay was going to be coaxing animals around obstacles to a specific location, Josh suggested I look into A* search. I vaguely recalled having studied A* in college and wound up following the excellent article A* Pathfinding for Beginners. The first hurdle I had to cross was deciding the level of detail for my A* grid: our game targets 720p and 1080p TV resolutions 1, but since this game has to run on a decent-but-not-amazing Android device which I have no way of testing with, I figured trying to search pixel-by-pixel was going to use more memory than we had available (not to mention time). So I decided to pick an arbitrary reasonable size and landed on 160x90: I figured 10x the aspect ratio of 16:9 would probably give us enough detail.

So, uh, how do I keep track of where the animals can walk and where they can’t?

The LibGDX sample apps came to the rescue again: the Cuboc demo does something very clever to build its level map: it loads a PNG and builds its in-memory level information based on the color values of the pixels in the image. This is probably common practice for a lot of game-dev folks, but this was a new approach to me and struck me as very clever. So I copied it. I made a simple black-and-white image, 160x90 pixels, which showed roughly where the barriers were in our temporary game level. Then I just loaded it into a giant boolean array of arrays in memory (14,400 booleans doesn’t actually take up much memory, thankfully).

A 2x version of the collision map I drew for our basic testing map.
A 2x version of the collision map I drew for our basic testing map.

Now that I knew which grid points where invalid, I could skip them when doing A* searching. Once I fixed a few2 bugs in my A* implementation, I could miraculously draw paths out of grid squares from an animal to an arbitrary location on screen, avoiding obstacles:

The green path is where I want the Panda to go. I just haven't figured out how to get it there yet.
The green path is where I want the Panda to go. I just haven't figured out how to get it there yet.

Now, I just had to figure out how to tell the animals to move along the path. This turned out to be quite a bit harder than expected, because as I soon learned, I couldn’t remember anything at all about geometry. Next time: VECTOR MATH.

  1. That would be 1280x720 and 1920x1080 respectively. 

  2. okay, a lot