Archive for the ‘Swift’ Category

Musing on API names for trailing and functional closures

When a call returns a value, I almost always use in-line closures. I prefer to surround functional calls with parens. I know my style is not universally popular, as many developers prefer the look of raw braces. It’s not uncommon to see calls like this:

numbers.sorted { $0 < $1 }.forEach {
  print($0)
}

The functional sort is chained to the non-functional loop, both using braces. Mandatory functional parens do two things. They differentiate expressions and they add the clarity of role labels that are lost with trailing closures. Compare these with the preceding call:

numbers.sorted(by: { $0 < $1 }).forEach {
  print($0)
}

// or even

numbers.sorted(by: <).forEach { print($0) }

In each case, the combination of name and label (in this case, sorted(by:)) is clearer and more easily read. Many APIs are designed without initial labels for Void-returning closures. They’re intended from the start to act as language-like constructs, so adding labels is either superfluous or detracts from the call when omitted:

public func forEach(_ body: (Self.Element) throws -> Void) rethrows

Omitting labels shouldn’t cloud intent even when a closure meant for functional calls is used. I could imagine common API naming rules to help guide labels and functional use (for example, “omit labels for Void-returning closure arguments” or “include role hint labels for functional closure arguments used to process and pass through values”).

Such rules might help but there’s one class of closures that doesn’t normally follow. Completion handlers, especially those sourced from Cocoa and Cocoa Touch, are almost always labeled as completion or some close variant. They’re designed for non-returning (and often asynchronous) execution. For example, you might see:

func run(_ action: SKAction, completion block: @escaping () -> Void)

or

func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

These items are normally called as trailing closures, so why shouldn’t their API naming follow suit? Wouldn’t it make more sense to have _ completionBlock: or _ completionHandler: than to use explanatory labels that are most commonly hidden when called?

What do you think? Let me know.

Iterating across more than two sequences at a time in Swift

A few days back, I needed to iterate three sequences at once. While Swift supports zip, allowing you to zip two sequences together and iterate across item pairs, until variadic generics hits the language, there’s no way to directly zip three or more.

Until that kind of tech hits the language, you can construct nested tuples for your occasional zip-3 or zip-4 needs without overly straining readability as in this example:

for (value1, (value2, value3)) in zip(seq1, zip(seq2, seq3)) {
  // use value1, value2, value3
}

I thought I’d leave this here in case it was of help to anyone.

Swift 5 Interpolation Part 3: Dates and Number Formatters

I’ve already posted about using string interpolation to customize Optional presentation and for coercing integer values via radix and to conditionalize text, and yet there is still so much more you can do with this new language feature.

Consider formatters. Both Swift and Cocoa/Cocoa touch support a number of these, ranging from numbers and currency to dates and times. They are a natural interpolation fit.

For example, dates are easy right out of the box. Just pass a formatter and you’re done. Note that I skip the formatter label. You’ll see why in just a second.

public extension String.StringInterpolation {
  mutating func appendInterpolation(_ value: Date, _ formatter: DateFormatter) {
    appendLiteral(formatter.string(from: value))
  }
}

For dates, it’s more about how do you create formatters than about interpolating them. Here’s the design I’m using right now:

public extension DateFormatter {
  /// Returns an initialized `DateFormatter` instance
  static func format(date: Style, time: Style) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale.current
    (formatter.dateStyle, formatter.timeStyle) = (date, time)
    return formatter
  }
}

For example:

print("\(Date(), .format(date: .short, time: .none))") // 12/16/18

I left off the formatter: label because the call to format documents the role of the second argument.

I initially went with a convenience initializer, along the same lines, but the calls were uglier:

print("\(Date(), DateFormatter(date: .none, time: .long))") // 8:20:15 AM MST

I also tried static preset properties and option sets, as well as dateStyle:timeStyle: interpolation arguments as but none of them really felt as readable as the format(date:time:) approach.

Number formats are a bit harder as they only work with NSNumber, which means you either have to create interpolators for both BinaryInteger and FloatingPoint, or you have to use some magic. Brent Royal-Gordon tried helping me work with _ObjectiveCBridgeable but I couldn’t get it to work. For some reason, Swift just wouldn’t pick up, for example, Double.pi as a bridgeable value.

For right now, I have this, which I’m not particularly happy with:

public extension String.StringInterpolation {
  /// Interpolates a floating point value using a
  /// number formatter.
  mutating func appendInterpolation<Value: FloatingPoint>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
  
  /// Interpolates an integer value using a number formatter
  mutating func appendInterpolation<Value: BinaryInteger>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
}

Creating number and currency formatters with NumberFormatter() is an ugly and tedious task. For example, here’s a formatter that sets rounding, localization, padding, and digit count:

let formatter = NumberFormatter()
formatter.localizesFormat = true
formatter.roundingMode = .halfUp
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 4
formatter.paddingPosition = .beforePrefix
formatter.paddingCharacter = "0"
formatter.minimumIntegerDigits = 5

"\(Double.pi, formatter: formatter)" // 00003.1416
"\(5, formatter: formatter)" // 00005.0

There really should be better and Swiftier ways to express these formatting preferences. For one thing, the minimum and maximum stuff could be expressed as ranges specific to the whole and fractional parts. I’m not convinced there should be just one formatter type devoted to handling integers, floating point numbers, and currency. Why not three?

Integers, to my best understanding, don’t need to worry about localization. And why not throw radix control into the IntegerFormatter mix while you’re at it? I’d imagine a well-designed integer formatter would easily replace my radix/prefix/bytewise/width interpolation that I used in a recent post.

In fact, I think I’ll design exactly that. Off to Xcode…

Some fantastic coverage of interpolation from Olivier Halligon here: Part 1 and Part 2.

My prosaic kicking the wheels repo is over at GitHub.

(And I’m trying to redesign Olivier’s attributed strings because somehow I feel they should be enumeration cases with associated value payloads rather than static members.)

More fun with Swift 5 String Interpolation: Radix formatting

I’m still kicking the tires and enjoying the new string interpolation features in Swift 5. Today’s extension enables (optionally padded) radix-based interpolation. You interpolate a number and specify a radix, the numerical base used to present it.

For example:

"\(42, radix: .hex)" // 2a
"\(42, radix: .binary)" // 101010
"\(42, radix: .octal)" // 52
"\(0x2a, radix: .decimal)" // 42
"\(15, radix: .hex, prefix: true, toWidth: 2)" // 0x0F

With padding you can ensure, for example, that a non-wide color is presented using two digits per color, with or without a prefix. Start with 15 and end up with F, 0F, or 0x0F , as desired.

It’s a simple extension for a task I use pretty regularly. I decided to use lowercase prefixes (0x and 0b) and uppercase hex (7F vs 7f). If you’d rather swap that out, change the prefix property and/or the first line in the interpolation:

public extension String.StringInterpolation {
    /// Represents a single numeric radix
    enum Radix: Int {
        case binary = 2, octal = 8, decimal = 10, hex = 16
        
        /// Returns a radix's optional prefix
        var prefix: String {
             return [.binary: "0b", .octal: "0o", .hex: "0x"][self, default: ""]
        }
    }
    
    /// Return padded version of the value using a specified radix
    mutating func appendInterpolation<I: Binary Integer>(_ value: I, radix: Radix, prefix: Bool = false, toWidth width: Int = 0) {
        
        // Values are uppercased, producing `FF` instead of `ff`
        var string = String(value, radix: radix.rawValue).uppercased()
        
        // Strings are pre-padded with 0 to match target widths
        if string.count < width {
            string = String(repeating: "0", count: max(0, width - string.count)) + string
        }
        
        // Prefixes use lower case, sourced from `String.StringInterpolation.Radix`
        if prefix {
            string = radix.prefix + string
        }
        
        appendInterpolation(string)
    }
}

I haven’t had a chance to test this much so if you see any issues, please let me know.

I have more to follow with more general NumberFormatter approaches that extend the interpolator (thanks, Dave DeLong!) and some fun suggestions and examples that will cover the new custom string delimiters.

Update James Dempsey writes:

In your post “More fun with Swift 5 String Interpolation: Radix formatting”, I noticed one very minor thing. The String initializer that takes a value and a radix also has an uppercase parameter. So the code
var string = String(value, radix: radix.rawValue).uppercased()
could be
var string = String(value, radix: radix.rawValue, uppercase: true)
I’m guessing that saves the tiny bit of work of creating a new string and transforming the old string. Definitely a minor point, but I always enjoy and find useful the precision of your explanations, so I thought you’d be interested.
Thank you, James!

The Beauty of Swift 5 String Interpolation

Thanks to SE-0228, you can control exactly how you want string interpolations to print. Thank you Brent for giving this to us. It’s a doozy! Let me share some examples.

Consider printing optionals. You use:

"There's \(value1) and \(value2)"

And get an instant warning:

You can click the fixes to suppress the warning but you’ll still get an output that looks like this: “There’s Optional(23) and nil”.

"There's \(String(describing: value1)) and \(String(describing: value2))"

Now you can strip the “Optional” and produce “There’s 23 and nil”, allowing you to print values directly:

extension String.StringInterpolation {
    /// Provides `Optional` string interpolation without forcing the
    /// use of `String(describing:)`.
    public mutating func appendInterpolation(_ value: T?, default defaultValue: String) {
        if let value = value {
            appendInterpolation(value)
        } else {
            appendLiteral(defaultValue)
        }
    }
}

// There's 23 and nil
"There's \(value1, default: "nil") and \(value2, default: "nil")"

You might create a set of styles and custom interpolation to support consistent presentation for optional output:

extension String.StringInterpolation {
    /// Optional Interpolation Styles
    public enum OptionalStyle {
        /// Includes the word `Optional` for both `some` and `none` cases
        case descriptive
        /// Strips the word `Optional` for both `some` and `none` cases
        case stripped
        /// Uses system interpolation, which includes the word `Optional` for
        /// `some` cases but not `none`.
        case `default`
    }
    
    /// Interpolates optional values using a supplied `optStyle` style
    public mutating func appendInterpolation(_ value: T?, optStyle style: String.StringInterpolation.OptionalStyle) {
        switch style {
        // Includes the word `Optional` for both `some` and `none` cases
        case .descriptive:
            if value == nil {
                appendLiteral("Optional(nil)")
            } else {
                appendLiteral(String(describing: value))
            }
        // Strips the word `Optional` for both `some` and `none` cases
        case .stripped:
            if let value = value {
                appendInterpolation(value)
            } else {
                appendLiteral("nil")
            }
        // Uses system interpolation, which includes the word `Optional` for
        // `some` cases but not `none`.
        default:
            appendLiteral(String(describing: value))
        }
    }
    
    /// Interpolates an optional using "stripped" interpolation, omitting
    /// the word "Optional" from both `.some` and `.none` cases
    public mutating func appendInterpolation(describing value: T?) {
        appendInterpolation(value, optStyle: .stripped)
    }

}

// "There's Optional(23) and nil"
"There's \(value1, optStyle: .default) and \(value2, optStyle: .default)"

// "There's Optional(23) and Optional(nil)"
"There's \(value1, optStyle: .descriptive) and \(value2, optStyle: .descriptive)"

// "There's 23 and nil"
"There's \(describing: value1) and \(describing: value2)"

Interpolation isn’t limited to tweaking optionals. Say you want to control whether a string is added without having to use a ternary expression with an empty string:

// Include on success (Thanks, Nate Cook)
extension String.StringInterpolation {
    /// Provides Boolean-guided interpolation that succeeds only when the condition
    /// evaluates to true.
    mutating func appendInterpolation(if condition: @autoclosure () -> Bool, _ literal: StringLiteralType) {
        guard condition() else { return }
        appendLiteral(literal)
    }
}

// Old
"Cheese Sandwich \(isStarred ? "(*)" : "")"

// New
"Cheese Sandwich \(if: isStarred, "(*)")"

There’s lots more you can do and it’s all exciting and fun.

Prototyping CoreGraphics in the Playground

No matter how flaky, I love using playgrounds to prototype Core Graphics, SpriteKit, and many other see-as-you-go technologies. They’re fantastic for building out specific custom content with a bare minimum of coding investment. You get a lot of win for very little time.

I was helping someone out the other day, explaining the strokeEnd keypath (versus the path keypath) and building a playground showed it off to perfection.

Admittedly, it helps to have quick helper code on-hand for quick starts. I have playground-specific setup code, handing me a view controller (called vc) and a centered view, ready to start demo-ing in this one.

I also have a couple of pages of code (like the layer(path:) constructor, the animateStrokemethods, and the schedule() utility off page, in the support module. They’re all highly reusable. It’s a pity in-playground debugging is so dreadful. It would be an ideal module-building tool if not for that: build and explore (and ideally build tests) in a single place, without having to be in a fixed workspace lacking the exploration feature. Adding “convert this exploration into a test” would be icing on top.

I’m disappointed that playground-specific visualizations built for teaching and demos don’t transfer to the debugger for real-world production support. I don’t see any reason why a CGPoint instance should get a pretty graphic representation but a CGAffineTransform, for which I have quite a full presentation, does not.

I can use custom mirroring to produce valuable output for dump, and therefore for printing objects in the debugger but not for debug quicklooks. Plus as far as I can tell the custom NSObject-only quicklooks haven’t been updated in years and there’s no hint of extending this to structs and enums.

By the way, what’s the deal with all the API audits? How long are these going to go on? If you thought updating the app delegate was a minor nuisance, you haven’t seen what’s happened to all the constants and Core Graphics APIs. This update is huge and disruptive…

Unwinding a modal segue on a single view controller

For whatever reason, my unwind segues for modal presentations weren’t working when my presenting source was my navigation’s root controller. This appears to be a common issue if you hunt around for “modal unwind doesn’t work”. A lot of the advice simply went: “You just can’t do that.”

After spending far too much time dealing with, I discovered that the autocomplete version, namely:

@IBAction func unwind(for unwindSegue: UIStoryboardSegue, towards subsequentVC: UIViewController)

doesn’t work. Instead, what you need is:

@IBAction func unwindFor(_ unwindSegue: UIStoryboardSegue, towards subsequentVC: UIViewController)

If you notice, the difference is unwind(for vs unwindFor(. I figured this out by implementing

func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool

and looking at the selector it expected to perform (specifically unwindFor:towards:). Moving the For outside fixed the problem and granted me a working unwind, allowing me to fetch state data from the modal controller and pass it back to the source.

I assume this issue arose because of the automatic translation of Cocoa APIs into Swift and I wonder if there are other issues that might arise from the same. Have you encountered such things? What are your thoughts?

 

Tuple Initialization

I’ve been wanting  tuple-initializable in Swift for Core Graphics, where it’s a drag to always use long and cumbersome initializers when I’m not building production code:

let point: CGPoint = (100, 50)

Yeah, it is better form to use labeled initializers but I’m anyone using CGPoint understands the correspondence between (x, y) coordinates. And I don’t want to just build CGPoint.init(_ x:, _ y:) extensions. I like the tuple form.

Right now, the closest you can get is the silly:

let point = (CGPoint.init as (CGFloat, CGFloat) -> CGPoint)(100, 50)

And that’s (pardon the pun) pointless.

It would be pretty cool to allow memberwise tuples with or without labels in place of  initializers when the tuple field types could be unambiguously determined:

let point: CGPoint = (x: 100, y: 50) 
// instead of: let point = CGPoint(x: 100, y: 50)
let person: Person = ("Mary", nil, "Santos")
// instead of: let person = Person(first: "Mary", middle: nil, last: "Santos")

It may be ugly but it would be hella useful in Playgrounds.

Straw Poll: Unwrapping solutions

Swift should be able to mitigate two issues related to forced unwrapping. First, it’s used as a bandaid by developers new to the language who want to make their code compile. Second, developers should be able to provide code-level annotation support for why a guaranteed wrap cannot fail and provide runtime diagnostics in any “Black Swan” scenario where they do. These items are discussed further in this proposal.

Please let me know which of the following designs you prefer. Each contains a link to a code solution. (The first item in the list (“Unwrap or Die”) links to a full proposal so scroll down to the design section.) The other two offer alternate designs. You can assume !! can be redesigned to support both throwing and Never solutions just as easily as fail or ??. The proposal goes into detail as to why that was not the original design, as doing so fundamentally changes nil-coalescing semantics.

Thank you in advance for your feedback and/or participation in the survey.

link to poll

Creating a low-cost ADD/ADHD refocusing band

My middle child recently had an evaluation regarding her processing and retention in reading. She has diagnosed ADD, and aside from the specific results of her tests, the specialist recommended we look for and purchase a device that would buzz her wrist at regular intervals when doing homework and reading. The goal is to refocus when one is easily distractable. It’s a bit like Apple’s “stand up and move” reminder.

However, when we headed over to Amazon, we were met by two realities. First, these things cost a lot. Second, they have terrible reviews. It occurred to me that I could probably put together a band with things we already had around the house.

Last summer, I did a little work exploring BLE, the low energy form of Bluetooth that works with iOS. My test platform was the 1st generation Mi Band step tracker, which I purchased for under $20. The second generation is similar and appears to cost under $30. (Here’s a link to the first gen model, which is sold by third parties.)

My build consisted of the following components:

  • I built a basic single-view app and added a single centered segmented control. The control specifies the time-out interval, which is simply a standard Timer.
  • When the Timer activates, it uses my Bluetooth helper type to write a single byte to the band, which causes it to buzz. It’s slightly more complicated than that because the code needs to scan for the device, discover it, stop scanning, and then write to the peripheral, but that’s all covered in my previous posts.
  • To keep the app running longer than 3 or 10 minutes in the background, I resort to the standard “play a silent wav file over and over”. I based my code on this simple github repo, which handles audio interrupts and restarts.
  • I added every background mode I thought potentially applicable: plays audio/video streams, uses CoreBluetooth, provides VoIP services. I could probably have dropped the first one but it does no harm so I kept it.

Testing was, as you’d expect, a bit tedious, especially trying to figure out whether I had beaten the automatic time out (which is why went from my custom code to the github version for keeping alive). I put the pedometer portion on an empty diet coke can, to make it buzz a lot louder without having to wear the band.

In the end for a few hours of my time and under $20 capital investment, I ended up with a handy little tool. My daughter has only been using it a few days so it’s still too early to see whether the refocusing component is actually effective.

If you want to give this a try, I’ve put up gists for the primary view controller and the bluetooth controller. You can grab the background handler from the above github  repo link. I didn’t bother cleaning up any of my code, so it is what it is, which is a working prototype. Don’t forget to add the background modes to your Info.plist.

If you build this yourself (or just intend to try it out), drop me a note or a comment and let me know how it goes.