Structs, Part 2

Another day, another day of 100 Days of Swift. This morning I finished off the section on structs, and once again I learned a few new things.

First of all, lazy properties were kinda new to me. I had heard about them, but I don’t think I remember ever using them. Let’s take a look. Note that quip in this example doesn’t get initialized until it’s used in the print statement.

struct Janitor {
    var name: String
    var show: String
    lazy var quip = "Don't get me started."
    
    init(name: String, show: String) {
        self.name = name
        self.show = show
    }
}

var scruffy = Janitor(name: "Scruffy", show: "Futurama")
print(scruffy.quip)

The other thing I noticed this week was that while I’ve used static methods quite a bit, I can’t remember having used static properties.

struct Node {
    var taxonId: Int
    var rankName: String
    var name: String
    
    static let Life = Node(taxonId: 48460, rankName: "State of Matter", name: "Life")
}

print("All taxa in the tree descend from \(Node.Life.rankName) \(Node.Life.name).")

Structs, Part 1

Hey guys, it’s Alex!

Another 100 Days of Swift blog post, this morning I was working through Day 8, Structs part 1. Once again I was aware of the basics of structs, having used them quite a bit, but I still learned a bunch from today’s exercises.

The first thing that was new to me was property observers in structs. This seems like a feature that I’ll get a lot of mileage out of:

struct ImageClassifier {
    var fps = 60
}

struct Camera {
    var classifier: ImageClassifier
    var fps: Int {
        didSet {
            classifier.fps = fps
        }
    }
}

Something else new to me was mutating methods on structs. Since at struct definition time, Swift won’t know whether a struct is a constant or a variable, you can use this hint so that Swift knows that your mutating method will only be callable on variable instances of this struct:

struct Artwork {
    var title: String
    var artist: String
    var isSold: Bool
    var owner: String?
    
    mutating func sold(to newOwner: String) {
        isSold = true
        owner = newOwner
    }
}

var jetFighter = Artwork(title: "Düsenjäger", artist: "Gerhard Richter", isSold: false, owner: nil)
jetFighter.sold(to: "Zhang Chan")
jetFighter.sold(to: "Cheyenne Westphal")

I’d never really given much thought to what type strings or arrays are in Swift. I think I assumed that strings were probably classes, based on NSString but it’s cool to see that they’re structs. Swift arrays, tho, had me totally fooled. Was it based on NSArray, or was it a base data type of the language like C arrays, or something else? I have to admit I’d never thought about it, so it was cool to learn that Swift arrays are also structs. Since Swift is open source, including the standard library, you can actually find the definitions here and here. Yep, they’re structs.

I also learned two methods, one on string and one on array, that I think I’ll use. First, string’s hasPrefix() method will come in handy:

let courseSchedule = [
    "CS 101",
    "CS 232",
    "HSTEU 401",
    "HSTAA 299",
]

let csClasses = courseSchedule.filter {
    return $0.hasPrefix("CS")
}

Also, I’ll be using the array method firstIndex(of:) instead of index(of:) since the latter has been deprecated. Here’s a kind of made-up example from how you might implement part of a UIPageViewController which also shows endIndex and index(after:):

func pageViewController(_ pageViewController: UIPageViewController,
                        viewControllerAfter viewController: UIViewController) -> UIViewController? {

    guard let currentIdx = orderedViewControllers.firstIndex(of: viewController) else {
        assert(false, "couldn't get idx of a view controller in orderedViewControllers")
        return nil
    }
    
    if (currentIdx == orderedViewControllers.endIndex) {
        return nil
    } else {
        let nextIdx = orderedViewControllers.index(after: currentIdx)
        return orderedViewControllers[nextIdx]
    }
}

Closures, Part 2

I’ve done a full week of 100 Days of Swift, which means I’m 7% of the way done, right?

Today was more brain twisting closures. Happily I feel like I grok them a little better today than I did a week ago, so that’s progress. Two things stand out to me as new things I learned today: shorthand closure syntax and capturing values.

I’d come across the $0 syntax once or twice but I hadn’t known how much boilerplate could be removed in trailing closure calling syntax. You can even remove the return statement in a one line closure block:

func eatSushi(action: (String) -> String) {
    let description = action("Salmon")
    print(description)
}
eatSushi { (food: String) -> String in
    return "I'm noshing on some \(food)"
}
eatSushi {
    return "I'm eating up some \($0)"
}
eatSushi {
    "I'm almost full of \($0)"
}

Another thing that I knew was possible was capturing values in a closure. I’d come across it in javascript, and it’s also just part of the definition, that a closure captures values that are used locally but are defined in an enclosing/outer scope. Anyways, cool to see the syntax explicitly laid out in Swift:

func readComic() -> (String) -> Void {
    var comicsRead = 0
    return {
        comicsRead += 1
        print("After reading \($0), you've read \(comicsRead) comics.")
    }
}
let reader = readComic()
reader("The Girl from H.O.P.P.E.R.S")
reader("Transmetropolitan")
reader("King City")
reader("Black Monday Murders")

Now off to work on MFArtist a little bit!

Closures, Part 1

Another day, another day of Swift. For today’s 100 Days of Swift challenge, I learned a bunch about closures.

For the most part, my experience with closures in Swift and Objective-C has been on the order of “this is a magic incantation, look it up on Fucking Closure Syntax or in a library every time I want to do anything that requires a closure.” It’s the Stack Overflow style of hacking together software. Also, I’ve generally only used closures in the context of asynchronous network calls, where half the battle is just figuring out how to update the UI in an async way without creating a retain loop.

It felt good to be learning how closures work more fundamentally.

Functions

It’s a new day, which means another day of 100 Days of Swift. Today was all about functions. Like previous days, I knew the most obvious bits pretty well, but I still learned some useful tidbits.

First of all, while I was aware of the _ syntax for omitting parameter names, I wasn’t explicitly aware that it was part of a larger system of parameter labels. This is probably easiest to understand in the context of prepositions:

func give(_ gift: String, to recipient: String) {
    print("\(recipient) thanks you for the \(gift).")
}
give("Baseball Tickets", to: "Erika")

Another piece of syntax that was new to me was default parameters:

enum PlayStyle {
    case AD
    case AP
}

func playKennen(_ style: PlayStyle = .AP) {
    if style == .AP {
        print("Win hard or lose hard")
    } else {
        print("Tank killer")
    }
}

playKennen()

Something else that I knew was possible, but didn’t know the syntax for was variadic functions. It feels a little odd to me that the parameter type magically changes to a list, but I guess it makes sense:

func gratefulFor(_ gratitude: String...) {
    for gratitudeItem in gratitude {
        print("Today I'm grateful for \(gratitudeItem).")
    }
}
gratefulFor("coffee", "swift", "wwdc videos")

Finally, while I’d seen inout function parameters once or twice, and I knew of call by reference for errors and such in Objective-C, I hadn’t seen the syntax for declaring a function with an inout parameter in Swift yet. It’s not something that I think I’ll need very often, but here’s an example (adapted from Stack Overflow):

struct Vector3 {
    let x: Float;
    let y: Float;
    let z: Float;
}

func + (left: Vector3, right: Vector3) -> Vector3 {
    return Vector3(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z)
}
func += (left: inout Vector3, right: Vector3) {
    left = left + right
}

var first = Vector3(x: 1, y: 3, z: 2)
let second = Vector3(x: 3, y: 2, z: 1)
first += second

With that, I’m off to spend the next 30 minutes of my day with Swift working on MFArtist.