Archive for June, 2015

Swift: Do? There is no do. There is no do not. There is just try!

play-volleyball-4-1179000-m

As Yoda may not have put it, “try or try not, there is no do”. Although strictly speaking, there is a do. In fact, there’s quite a lot of do{} in Swift 2.0. At the same time, there’s also try. And, quite interestingly, there’s also try!.

You call throwing functions using the try or try! operators. Try! (known to its closest friends as try-with-an-exclamation-point) is the forced-try expression. It enables you to skip the do-catch-tango of doom handling.

Forced-try wraps your call in a runtime assertion made with the highest quality asserts lovingly crafted by artisan compilation and disables error propagation. In a nutshell, it throws a run-time error instead of passing errors to handlers for in-app resolution.

So why would you use this? Try! is for calls that throw but that you pretty much know a priori will never fail. As a rule, don’t try! unless you’re sure a throwing function isn’t going to throw.

Try! is also handy for quick playground hits where you just want something to run, and you don’t really care if it fails and crashes.

A forced-try basically says, “Just go ahead and perform this throwing operation and if it fails, so be it.”

Fun facts:

  • The throws keyword is automatically part of a function’s type. Non-throwing functions are subtypes of throwing functions. So you can use the try operator with non-throwing functions.
  • When currying the throws applies only to the innermost function.
  • You can’t override non-throwing methods with throwing ones but you can override a throwing method with a non-throwing method.
  • Throwing functions cannot satisfy protocol requirements for non-throwing functions but you can satisfy a throwing requirement with a non-throwing implementation.

Swift Developer Challenge: Create a deck of cards

The deck-of-cards enumeration keeps coming up over and over again in #swift-lang because of the Swift Programming Language guided tour. I recently decided to create my own deck. I started on this because I wanted to test out some of GameplayKit features, namely shuffling, but also because I wanted to play a bit with CustomStringConvertible and CustomPlaygroundQuickLookable.

My goal was actually to build card views, shuffle a deck, and fan out the results. What I found was that the Unicode deck characters won’t render properly to UIKit contexts, where GameplayKit is freely available, and will to OS X ones, where GameplayKit isn’t. (I’m still primarily on Yosemite, not El Capitan.)

I filed some radars, created a post, and put my implementation to the side. Then Maximilian tweeted.

So here’s a developer challenge. Have at the deck enumeration, have some fun, and share your implementation on github. When you’re ready to peek, here’s mine.

Swift: Little things that still drive me nuts

UIGraphicsGetCurrentContext() should either throws or be optional. It isn’t. It’s func UIGraphicsGetCurrentContext() -> CGContext.

Screen Shot 2015-06-22 at 4.56.45 PM

So right now when I either try or if let, I can’t. I can’t even if context == nil, which means I have a lot of code I need to annotate with TODO and hope that I remember to come back to it.

For now, I’m just assuming the value returned is valid:

/// Perform a drawing transaction without 
/// affecting general graphics state
public func PushDraw(block: () -> Void) {
    let context = UIGraphicsGetCurrentContext()
    CGContextSaveGState(context)
    block()
    CGContextRestoreGState(context)
}

21494444

Swift: Dancing the Error Mambo

The Swift Programming Language book writes, “In Swift, errors are represented by values of types conforming to the ErrorType protocol…Swift enumerations that adopt ErrorType automatically have the implementation of their conformance synthesized by the compiler.”

The entire documentation currently in the Standard Library for ErrorType outside the book is this:

Screen Shot 2015-06-21 at 12.47.18 PM

Which, you know, right?

I did finally get non-enum error working. Thought I’d share.

public struct Error: ErrorType {
    // Required but currently undocumented
    public var _domain: String {return "com.sadun"}
    public var _code: Int {return 0}

    // My custom bits
    var reason: String
    var source: String

    // Initializer only requires a reason
    // The working inline macros are courtesy of Mike Ash
    public init(_ reason: String, 
        source: String = __FUNCTION__, 
        file: String = __FILE__, 
        line: Int = __LINE__) {
            self.reason = reason
            self.source = "Thrown in \(source) (File: \(file) Line: \(line))"
    }
}

You implement the _domain and _code properties. Otherwise the rest of the ErrorType is handled for you by default protocol implementations.

Here’s an example of what this error looks like:

Screen Shot 2015-06-21 at 12.51.57 PM

You get more file information (beyond <EXPR>) outside of playgrounds.  Somewhat sadly, in an OCD way, I’m weighing whether to adjust the casing and punctuation to match the results from fatalError():

Screen Shot 2015-06-21 at 12.54.44 PM

I’ve also recently written about asynchronous errors.

Swift: New favorite workaround hack

Screen Shot 2015-06-21 at 5.30.20 PM

Instead of using complicated if #available and @available workarounds on everything, add a single guard #available to the top of your playground. Thanks to Jack Lawrence.