Archive for the ‘Swift’ Category

Bluetooth Lessons I: Manager and Scanning

Last June, Izzy inspired me to do something with Bluetooth and playgrounds but honestly, I haven’t had the time and I couldn’t afford a Sphereo. I’ve wrapped up Swift Style. Attempting to write meaningfully about drawing while the Denver Public School system has for reasons I cannot begin to comprehend released my child to my recognizance for two entire weeks seems unlikely. (Another child has half days. Fun.)

To prepare, I purchased one of the cheapest BLE devices I could find, a Mi wristband (Amazon cost under $20 shipped), which has a reverse engineered API that lets you control vibration. A friend of mine just purchased the hugely expensive Buzzies for Autism bands. I’m  hoping I can mimic some of that functionality with a playground, a low-rent BLE device, and a full-price child.

Have I mentioned recently how awesome playgrounds are for playing around with and learning about new tech? They really are, especially because you can integrate just one concept at a time, and then test it live before expanding to the next.

I decided to go with Cocoa for my BLE exploration instead of iOS, although the tech is more or less the same on both platforms. When you work in Cocoa, using a macOS playground, the startup speed is phenomenal because you don’t have to work with a simulator.

My first project simply sets up a central manager (CBCentralManager), monitors its state, and lists any devices it finds. I’m pretty happy for this as a first day, not many hours to spend on it, playing around and doing something marginally useful result.

The CoreBluetooth documentation is pretty dire. For example, this is the Swift docs for CBManagerStatePoweredOn.  After SE-0005, the constant is actually .poweredOn, as you see in the following sample code, not CBManagerStatePoweredOn. And there’s no documentation in that documentation.

Nonetheless, I persevered and my first child-full day produced a basic helper class. You really need to work in NSObject land for this because of all the delegation. So I set up an objc-friendly class, set it as a manager delegate, and implemented the one required callback method, which follows the manger state.

Try sticking the Bluetooth icon in your system menu bar.  (System Preferences > Bluetooth > Show Bluetooth in menu bar.) It’s a lot of fun to toggle it on and off and watch your playground keep tabs on that state.

Next, I added a basic peripheral scan. You need to scan only when the manager achieves poweredOn state.

Apple writes, “Before you call CBCentralManager methods, the state of the central manager object must be powered on, as indicated by the CBCentralManagerStatePoweredOn constant. This state indicates that the central device (your iPhone or iPad, for instance) supports Bluetooth low energy and that Bluetooth is on and available to use.”

That’s why I added the scan to the playground’s “update state” callback. You’ll want to stop scans when the BLE powers off.

Finally, I implemented one more callback, which asynchronously lists discovered peripherals. It picked up nicely on my Apple TV and when I enabled and disabled a hotspot on my iPhone. Great fun.

Here’s the code involved. You can see how very short it is. The struggle wasn’t in the lines of code or complexity, it’s mostly about how very badly documented most everything seems to be.

I’ll post more as time allows.

https://gist.github.com/erica/d249ff13aec353e8a8d72a1f5e77d3f8

The problem with macOS and Drawing

Trying to write cross-platform code for drawing routines is ridiculously frustrating. It’s never just a matter of creating cross-platform type aliases. UIColor and NSColor are cousins, not brothers. UIBezierPath and NSBezierPath are slightly more distantly related, especially when it comes to adding curves and retrieving an underlying cgPath.

Although a lot of tech debuts on Cocoa, it often gets refined in Cocoa Touch. That refinement doesn’t prioritize cross-platform development, so the “second time, better design” features that leap into iOS land are hard to support with a single code-base. (And yes, I’m looking at you layout constraints with their different dictionary types for metrics.)

Starting last year, UIKit drawing really improved. It already had several advantages over Cocoa drawing, but last year’s update pushed the APIs to a new level.

NSImage has its  init(size:flipped:drawingHandler:) initializer (introduced in 10.8). in iOS 10, UIImage adopted and refined that closure-based drawing approach to UIGraphicsImageRendererUIGraphicsImageRendererFormat, etc. A renderer can return an image or PNG/JPEG data. Very handy, very convenient, wide-color aware, nifty. And it phases out a lot of home-built solutions that devs had been using to get exactly those results.

The new features are not fully refined. For example, there isn’t a single doc comment across the entire feature suite. Which, you know, sigh. But the architecture is there if not perfect or final, and it’s several steps beyond the corresponding init on macOS.

With this new tech in place, I’m starting to wonder about some older APIs like Cocoa Touch’s drawing stack, which lets you push and pop contexts for immediate drawing. It’s handy for using UIKit calls to draw into custom Core Graphics bitmap contexts. Is that still going to be around and used after WWDC this year? Or next year? Or will it be subsumed into UIGraphicsImageRenderer? It looks ripe for redesign and replacement.

I also don’t think UIGraphicsBegin/EndImageContext is long for the world. It was first introduced in iOS 2. It may be deprecated in iOS 11. The new APIs feel more appropriate to the design and philosophy of iOS, and these calls always stood out as a very odd approach.

But let me get back to the issues of writing “Swift Drawing”. When it comes to book, platform dichotomy hits hard. To get a sense of how much effort it would take to write about drawing for both platforms, I worked on my blend mode appendix sample code this weekend.

This is extremely simple code. It just iterates through  the standard Core Graphics blend modes to create stock samples. The appendix describes each mode We’re talking about maybe a page of code. Getting it to Cocoa? Not so easy.

I put together a very rough skeleton granting Cocoa the basic abilities of Cocoa Touch. I’m not very happy with this code and I’m not sure I’m going to keep pushing on this code or developing its capabilities, which is why it’s in a gist and not a repo.

I suspect we may see new image APIs — both Cocoa and Cocoa Touch — this WWDC. I don’t want to compete with Apple APIs and I also don’t want to have to write two completely distinct drawing books: one for iOS and one for macOS.

So I’m still struggling because while most basic calls for CoreGraphics are interchangeable across platforms, the Cocoa and Cocoa Touch layers are not. If I go with samples that support both platforms, I have to pick one of the following approaches:

  • create an artificial UIKit for Cocoa (that is a disconnect for macOS readers),
  • create an unrealistic platform-independent backbone to unify Cocoa and Cocoa Touch, which means I can’t talk to Cocoa Touch readers in their native language (that is objectively bad), or
  • stick with Cocoa Touch like I did in the original book (simplest but excludes macOS readers).

After this weekend’s experimenting, I’m leaning towards keeping things mostly iOS-centric. I may mix in a bit of “fake UIKit”.

I know I don’t want to go the route of “Color”/”Font”/”BezierPath”/”LayoutConstraint” cross platform types that I use in my own development work. It’s fine to use pseudo-types and typealiases internally but it’s not a way to introduce native tech in a book. Books should teach to the platform with the least distance between the reader and the APIs. No dependencies, few workarounds, minimal obfuscation.

I could build a small set of “fake UIKit” calls for macOS samples. This would allow me to focus discussions on the true cross-platform features like gradients, paths, colors, and bitmaps, without having to write two entire books at once, but I’m not sure it’s worth the effort or the hardship on macOS readers.

The costs look like this:

  • Full macOS support would double my work.
  • Adding compatibility discussions and partial macOS code would add about 60% or more work.
  • A minimal “fake UIKit” and a few references in-book to this approach, I could probably squeak by with about 25-35%.
  • Based on initial feedback, macOS sales would be about 10% at most of my readers.

Bottom line: macOS is a big old monkey wrench for this particular project. After investing a weekend, I’m not sure I want to go there but I’m interested in hearing your feedback after looking at my samples and prototype gists.

Swift Drawing: Would you buy this book?

Over the years, I have received any number of letters, emails, and tweets asking if I were going to update my iOS Drawing book. I first wrote a version for Addison Wesley/Pearson as a kind of fun side project between major iOS releases and it was warmly received. Readers liked the practical solutions for low-level drawing and fancy effects.

Since then iOS evolved and Swift arrived. With new types like UIGraphicsImageRenderer and type extensions for structs like CGRect, drawing has a lot of updated power tools on hand and ready to deploy.  Using C-based APIs with Swift can be a bit tricky, so it might be nice to have some guidance and examples. Plus, playgrounds now make the perfect sample code platform.

So would you be a potential purchaser  if I wrote this? I updated about 25% already, just to get a feel for the changes (and I think they’re quite cool), and am looking at using Leanpub to roll out the book a bit at a time. I’m hoping there’s enough traction out there in potential reader-land to make this worth building. I’d anticipate finishing just before WWDC.

Thoughts? Interest? Please let me know. Thanks!

Dear Erica: Playground Support Folder

“N” asks: “Hey, is the “shared playground folder” long gone, or does it still exist?”

Still there, still useful.

The big difference for long-time playground users is that it moved into the PlaygroundSupport module from the XCPlayground module. The latter was deprecated in Xcode 7. It’s a tiny module that supports playground-specific features. This constant (playgroundSharedDataDirectory) gives you a well-defined sandboxed folder that’s shared between all playgrounds.

This is, by the way, a terrible symbol name (take note!), as it returns a URL. It used to return a string but the name never got updated:

public let playgroundSharedDataDirectory: URL

I often build playground-specific subfolders so my directory doesn’t get all messy.

Another valuable feature is indefinite execution support (needsIndefiniteExecution) for playground pages that have to perform asynchronous work before completion. You can use this support to build little playground-based utilities instead of writing shell scripts.

I have some pages that work with Imgur, Google search, Wolfram queries, etc. A nice thing about building in playgrounds vs shell is that you can integrate audio and visual elements rather than having to save them to files and open them in helper applications.

If you’re writing API utilities, enable manual execution. Constant reloads can almost immediately deplete, for example, your Gist API query count for the day. Oops.

In Xcode, the shared data folder is available for iOS, macOS, and tvOS playgrounds. The shared data folder is not available on iOS’s Swift Playgrounds. This policy discourages custom local storage and access beyond standard media library locations.

There are some further protocols and types under the PlaygroundSupport umbrella in Swift Playgrounds. These aren’t available for Xcode playgrounds because they’re meant for use in Playground Books.

The extra functionality is part of Playground Book support, which underlies the tech in “Learn to Code”, etc. These additional APIs include items like a key-value data store, message passing between the live view and the primary playground page, and more.

If you want to learn more about Playgrounds, I have a book.  It discusses the features you use in Xcode and an overview of how to use iOS Playgrounds. I quite deliberately did not include much about Playground Book authoring as the topics are somewhat orthogonal.

I’ll probably be revising both Playground Secrets and Power Tips and my Swift Documentation Markup after WWDC. There’s also a three-book bundle available with Swift from Two to Three.

Dear Erica: Snake Case

An anonymous reader writes, “Is there is ever a good reason to use snake case in Swift code?”

Although I’m tempted to respond with a snarky no_there_isn't, of course you’ll use snake case, and with good reason. The real world offers many legacy and non-native libraries. Coders often source snake case calls and constants in their production code.

When developing your own symbols, the Swift community consensus has centered on UpperCamel for type and protocol names and lowerCamel for members, freestanding functions, and other symbols. This is a non-binding convention but it will make your code look and feel more Swifty.

Swift 4: Release Process and Phase 2

Release Process

The Swift 4 release process targets Fall 2017:

Swift 4 is a major release that is intended to be completed in the fall of 2017. It pivots around providing source stability for Swift 3 code while implementing essential feature work needed to achieve binary stability in the language. It will contain significant enhancements to the core language and Standard Library, especially in the generics system and a revamp of the String type. More details can be found on the Swift Evolution page.

Swift 4 Phase 2

The Swift 4 two-stage release plan was established in July 2016: focusing on essentials and ABI stability.  Swift  4 only focuses on Phase 1 at this time. Stage 2 starts now.

All design work and discussion for stage 2 extends to April 1, 2017. The intent is to timebox discussion to provide adequate time for the actual implementation of accepted proposals.

Deferred ABI and Status Updates

Ted Kremenek writes,

Since July, we now have a much better understanding now of how to achieve ABI stability, with an ABI Manifesto https://github.com/apple/swift/blob/master/docs/ABIStabilityManifesto.md detailing the list of all language/implementation work that is needed to achieve ABI stability. We have made substantial progress in that work during stage 1, but much remains to be done. Once Swift achieves ABI stability the ABI can be extended, but not changed. Thus the cost of locking down an ABI too early is quite high.

Deferring ABI stability enables Swift to focus on language fundamentals. An ABI dashboard will be wired up from the Swift Evolution Github repository. This will present a table of remaining ABI tasks and display their status.

Foundation

Swift Foundation API improvements are folded under the phase 2 umbrella, “to continue the goal of making the Cocoa SDK work seamlessly in Swift. Details on the specific goals will be provided as we get started on Swift 4 stage 2.”

Unimplemented Proposals

The following accepted proposals are rolled forward into Swift 4 Stage 2:

  • SE-0104 “Protocol-oriented Integers”: This proposal requires revision and another round of review based on other changes that have been made to the language and standard library since acceptance.
  • SE-0075 “Adding a Build Configuration Import Test”: This is (still) an additive proposal and no other changes affect this proposal. It will be carried forward and considered accepted for Swift 4.
  • SE-0042 “Flattening the function type of unapplied method references”: This proposal requires another round of review. This is a significant source-breaking change, and the bar for such source-breaking changes is considerably higher in Swift 4 than it was in Swift 3.
  • SE-0068 “Expanding Swift Self to class members and value types”: This is (still) an additive proposal and no other changes affect this proposal. It will be carried forward and considered accepted for Swift 4.

Links

Swift Style: Now Available for Amazon Pre-Order

Swift Style is almost wrapped up. I’m just waiting for some final copy edits. Notably, pre-orders are live on Amazon. (You can ignore the dates, page counts, etc there. They’re just place-fillers.) I just did a product video for Amazon, which hopefully will be posted over the next few weeks.

Once printed, Style will be on sale at all the major retailers as well as at Pragmatic. Pragmatic gives you the option of hybrid ebook/printed bundles, and gives me a slightly better slice of the royalty pie, if that matters to you. It’s a nice thing for me.

I’ll be remote talking about the book and Swift Style at PlaygroundsCon on the 24th (the 23rd in the US) this month and Forward Swift 2 on March 2. I also recently gave a talk at Realm’s Swift user SLUG meetup, which you can watch by following the link earlier in this sentence.

That’s not to say this project is done. Swift Style evolved from talking to developers. It represents viewpoints from the larger Swift development community. That process can and will continue as people read the book and I expand its guidance. The people at Pragmatic have been lovely in helping me plan out the book’s future as well as its present.

Challenge: Filtering associated value enumeration arrays

The Challenge

Courtesy of Mike Ash, here’s the challenge. You have an enumeration:

enum Enum {
    case foo(Int)
    case bar(String)
    case qux(Int)
}

And you have an array of them:

let items: [Enum] = [.foo(1), .bar("hi"), .foo(2)]

Return a filtered array containing only one case, for example foo. The difficulty lies in that Swift does not seem to offer a == or ~= operator that works on cases, ignoring associated values:

// does not work
let filtered = items.filter({ $0 == .foo })

So what do you do?

Attempt 1

Here’s my first attempt. Super ugly but it gets the job done:

let filtered = items.filter({ 
    switch $0 { case .foo: return true; default: return false } })

Evan Dekhayser prefers if-case:

let filtered = items.filter({ 
    if case .foo = $0 { return true }; return false })

And you can of course use guard as well:

let filteredy = items.filter({ 
    guard case .foo = $0 else { return false }; return true })

Attempt 2

Just as ugly but slightly shorter in terms of number of characters. But it does more work than #1:

let filtered = items.filter({ 
    for case .foo in [$0] { return true }; return false })

Again, yuck.

Attempt 3

I really hate this approach because you have to implement a separate property for each case. Double yuck:

extension Enum {
    var isFoo: Bool {
        switch self { case .foo: return true; default: return false }
    }
}
let filtered = items.filter({ $0.isFoo })

Attempt 4

This is gross because it requires a placeholder value for the rhs, even though that value is never used. And no, you can’t pass an underscore here:

extension Enum {
    static func ~= (lhs: Enum, rhs: Enum) -> Bool {
        let lhsCase = Array(Mirror(reflecting: lhs).children)
        let rhsCase = Array(Mirror(reflecting: rhs).children)
        return lhsCase[0].0 == rhsCase[0].0
    }
}
let filtered = items.filter({ $0 ~= .foo(0) })

Attempt 5

Then I got the idea into my head that you could use reflection. If you don’t supply a value to an enumeration case with an associated value, it returns a function along the lines of (T) -> Enum. Here is as far as I got before I realized the enumeration *name* was not preserved in its reflection:

import Foundation

extension Enum {
    var caseName: String {
        return "\(Array(Mirror(reflecting: self).children)[0].0!)"
    }
    
    static func ~= <T>(lhs: Enum, rhs: (T) -> Enum) -> Bool {
        let lhsCase = lhs.caseName
        let prefixString = "Mirror for (\(T.self)) -> "
        let typeOffset = prefixString.characters.count
        let typeString = "\(Mirror(reflecting: rhs).description)"
        let rhsCase = typeString.substring(from: typeString.index(typeString.startIndex, offsetBy: typeOffset))
        return true
    }
}

Yeah. Really bad, plus it doesn’t work.

Call for solutions

Since I didn’t really get very far with this, I’m throwing this out there as an open challenge. Can you come up with a parsimonious, readable, and less horrible (I was going to say “more elegant”, but c’mon) way to approach this? I suspect my first attempt may be the best one, which would make me sad.

Non-contiguous raw value enumerations

Brennan Stehling recently uncovered a fantastic Swift feature I was completely unaware of. I knew you could create raw value enumerations that automatically incremented the value for each case:

enum MyEnumeration: Int {
   case one = 1, two, three, four
}

MyEnumeration.three.rawValue // 3

And I knew you could create raw value enumerations with hand-set values:

enum MyEnumeration: Int {
    case one = 1, three = 3, five = 5
}

But I didn’t know that you could mix and match the two in the same declaration! (Although, you probably shouldn’t do this for standards-based values like the following example…)

enum HTTPStatusCode: Int {
    // 100 Informational
    case continue = 100
    case switchingProtocols
    case processing
    // 200 Success
    case OK = 200
    case created
    case accepted
    case nonAuthoritativeInformation
}

HTTPStatusCode.accepted.rawValue // 202

How cool is that?

I’d probably reserve this approach for values with offsets (for example, “start at 1”), and where the underlying values don’t have established semantics. As Kristina Thai points out, skipping meaningful values doesn’t help readability or inspection.