Generics

Swift Generics

Generics in Swift… Seem intimidating? I know they seemed that way to me…at first. But think back, wasn’t there a time in your programming career where variables, loops, and functions seemed intimidating? Now, they most likely feel second nature. This is true for plenty programming concepts. At first, they can be scary, but once you dive in that doubt and confusion will quickly dissipate. So hold tight, in this post I am going to walk you through the basics of generics and some of the different ways they can be used.

The Basics

So…what are generics? First off, I am certainly not the first person to write about generics. There are plenty of resources out there. Just search “Swift Generics” and tons of resources will appear. But that is kind of a beautiful thing in itself. Some people can learn just fine from Apple Documentation, others from a nice tutorial, some from videos or screen casts, and still others from blogs. Though DRY is a great principle for programming, it does not apply as nicely to pedagogy. You never know what style, analogy, example, medium, etc will finally give you that oh-so-sweet “aha” moment - that beautiful rush of understanding that comes when you realize you finally “get it”. So, with any luck, perhaps this post will provide you your “aha” moment or, at the very least, perhaps it will give you a good idea.

Now, back to the technical concepts…what are generics? Well, its really in the name. Generics are a feature for taking classes, structs, enums, typealiases, protocols, etc, and making them…well…generic. All of our functions and objects reference other and objects such as Strings, Ints, Doubles, etc. But sometimes you don’t care about a specific type, you want to write your code for ALL types, or at least a subset of those types. To show an example of this, lets make our own generic data structure. Many times, when a developer wants to write an asynchronous function, they will use closures like this:

internal func fetchStringAsyncWithNormalClosure(arg: String, completion: (String?, Error?) -> Void) {
    if arg.isEmpty {
        completion(nil, ExampleError.emptyString)
    } else {
        completion(arg, nil)
    }
}

But this has a few issues:

  1. Verbosity - (String?, Error?) -> Void) is both ugly and long
  2. Developer Error:

Because String and Error are both optional, one could actually include both or neither in the result.

completion(nil, nil)
completion("Result", .someError)

Or, the consumer could forget to check one or the other.

fetchStringAsyncWithNormalClosure(arg: "someString") { str, error in
    guard let s = str else { return }
}

Really, our completion result should be exclusive. Either the result was successful or there was an error. Most of the time there is no middle ground. So, lets model that in an enum.

 public enum Result {
    case success(String)
    case error(Error)
 }

But there is one problem here…what if we want this result to be an Int? Or a Bool? Or really any other type? Here is where generics come in…instead of tying this enum down to just a single type, we can simply use generic type T. Like this:

public enum Result<T> {
    case success(T)
    case error(Error)
}

Now, Result can take be defined as any type T at compile time. Here is what our fetch function can look like now:

 internal func fetchStringAsyncWithResultClosure(arg: String, completion: (Result<String>) -> Void) {
    if arg.isEmpty {
        completion(.error(ExampleError.emptyString))
    } else {
        completion(.success(arg))
    }
 }

This is looking better already. Shorter syntax, no optionals, and exclusive results. The best part is we are adhering to the DRY principle by not repeating our Result enum for each type we might want to use it with. We simply write once and reuse.

But…we can take this one step further with the help of generics and typealiases. Though (Result<String>) -> Void) is certainly better than (String?, Error?) -> Void what if we could could get a little more concise and take out the ugliness of closure syntax? This is definitely a job for typealiases. But did you know that they can be generic as well?

public typealias ResultClosure<T> = (Result<T>) -> Void

Now we can simply write our fetch function like this:

internal func fetchStringAsync(arg: String, completion: ResultClosure<String>) {
    if arg.isEmpty {
        completion(.error(ExampleError.emptyString))
    } else {
        completion(.success(arg))
    }
}

Nice! And we can now call it like this:

fetchStringAsync(arg: "someString") { result in
    switch result {
    case .success(let str):
        print(str)
    case .error(let error):
        print(error)
    }
}

As you can see, generics can really help eliminate duplication of code as well as improve syntax.

But generics don’t need to simply be restricted to data structures. They can be used in functions as well! For instance, lets say I need to write a function that takes in an array of Ints, and returns true if all the Ints are equal, and false if they are not. This function might look something like this:

func areAllElementsEqual(_ elems: [Int]) -> Bool {
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        if elem != lastElem {
            return false
        } else {
            lastElem = elem
        }
    }
    return true
}

This code will certainly work, which is great. We have accomplished our task and can now move on. But…what if we now need the code to check if all Strings in an array are equal? Well…our first thought might be to simply copy and paste the previous function but modify the signature to accept an array of Strings instead of Ints. But that seems like an awful waste. We could also rewrite our function to accept and array of Any. Lets look at that:

func areAllElementsEqual(_ elems: [Any]) -> Bool {
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        switch elem {
        case is Int:
            if (elem as? Int) != (lastElem as? Int) {
                return false
            } else {
                lastElem = elem
            }
        case is String:
            if (elem as? String) != (lastElem as? Int) {
                return false
            } else {
                lastElem = elem
            }
        default:
            fatalError("This type cannot handle String(describing: elem)")
        }
    }
    return true
}

Notice, we need to switch on elem here to check the type. The operator == cannot be called on type Any for practical reasons, so we need to try to cast to any potential types we are interested in. If we haven’t matched that type, then we have to throw some sort of error, because…well what else would you do? Now, if you want to add any more types to this you simply add to the switch statement. Double? Give it another case. Float? Give it another case. Dog? Give it another case. This certainly is not very DRY. We are rewriting the same code over and over again! Not to mention, by using Any we are opening ourselves up to all sorts of runtime bugs that the compiler cannot catch. Wouldn’t it be nice if instead of declaring Any as our type of array, we could instead declare some arbitrary type? Well…generics to the rescue.

Lets rewrite this function with generics in mind.

func areAllElementsEqual<T>(_ elems: [T]) -> Bool {
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        if elem != lastElem { // compiler error - Binary operator '!=' cannot be applied to two 'T' operands
            return false
        } else {
            lastElem = elem
        }
    }
    return true
}

Now, this code won’t compile, but we will get to that later. Lets take a look at that T. Sitting between the angle brackets is our generic type. It doesn’t have to be called T. It could be anything we want. T is just a convention, but we could be more descriptive and call it Element. Names aside, what we are doing here is declaring that this function will be making use of a generic type. We must utilize type T somewhere in our function signature, so we will use it to declare our Array type. Now, we don’t need to worry whether our input is an array of Strings, Ints, or Doubles, as long as it is specified at compile time. But, there is something wrong here…this code will not compile. Why? Because not every type has the == operator defined! If I make a custom struct Dog but never implemented ==, this would never work. Thankfully, Swift is smart and type safe, so it catches this and will stop the build. So then, how can we guarantee that all elements T will have == defined?

Type Constraints

Some times just having a plain old type T generic will not cut it. It works fine for objects like Arrays, but that is because you don’t really need and specific functionality from an element in an Array. We just need it to exist. But for our cases, we need a way to ensure that our element can be equated to the other elements in the Array. This is where type constraints come in. Constraints allow us to restrict T down to a smaller subset, and in turn, T gains the functionality of that subset.

If you’ve been writing Swift code for even just a short time, you have probably come across the Equatable protocol. This is a rather simple protocol that requires the conforming type to implement the == operator. (I highly recommend making all of your types Equatable as well as Hashable - and with Swift 4.1 its dead easy.) So, if all elements conforming to Equatable have == implemented, lets leverage that. Lets rewrite our function using T with a constraint saying that T must be equatable.

func areAllElementsEqual<T: Equatable>(_ elems: [T]) -> Bool {
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        if elem != lastElem { // compiles!
            return false
        } else {
            lastElem = elem
        }
    }
    return true
}

Great, this code will now work. We have added the constraint Equatable to T, and now we can use == or != on our elements. We have now made our function fully generic and safe. Let’s try it out!

areAllElementsEqual<Bool>([true, false, false, false]) // compiler error - Cannot explicitly specialize a generic function
areAllElementsEqual([1, 1, 1, 1]) // true
areAllElementsEqual(["Hello", "Hello", "Hello", "Hello, World"]) // false

Notice that first call explicitly specifies that this function will be using the Equatable type Bool. This is actually not allowed, but don’t worry, the compiler will infer the type for you!

Also note in this function that there is no chance for a runtime error because we have guaranteed that only Equatable types can use this function. If we were to try and compile this with a non-Equatable type, we would get an error.

areAllElementsEqual(
    [
    SomeNonEquatableType(), 
    SomeNonEquatableType(), 
    SomeNonEquatableType(), 
    SomeNonEquatableType()
    ]
    ) // compiler error - In argument type '[SomeNonEquatableType]', 'SomeNonEquatableType' does not conform to expected type 'Equatable'

Associated Types

After reading through our example, you might be wondering, “Hey Luke, why can’t we just use Equatable as the argument type for the elems Array?” Good question! Let’s take a look at this. Say we re-wrote our function to do just that:

func areAllElementsEqual(_ elems: [Equatable]) -> Bool { //Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        if elem != lastElem { // compiles!
            return false
        } else {
            lastElem = elem
        }
    }
    return true
}

Wow, no need for generics. Nice! Uh-oh - compiler error :/ But why? This error can be quite confusing to see at first, but the bottom line is this: If a protocol has an Associated Type (which includes a reference to Self) then that protocol cannot be treated like a type. I.e. it cannot be cast to, used as an argument type, etc. It can only be used as a generic constraint. So then…what is an associated type? And why do they restrict the protocol so much?

What are Associated Types

Essentially, associated types are generics for protocols. In the same way that you can use generics to define some type T in a function or class, so too can you use Associated Types to define some generic type to be used in a protocol conformance. Let’s look at an example. Say we are defining some models to represent different smart phones. Some smart phones have biometric authentication. So we decide to create a BiometricAuthenticatable protocol like this:

struct iPhone8 {}
struct iPhoneX {}

protocol BiometricAuthenticatable {
    func authenticate(with data: ??) -> Bool
}

extension iPhone8: BiometricAuthenticatable {
    func authenticate(with data: ??) -> Bool {

    }
}
extension iPhone10: BiometricAuthenticatable {
    func authenticate(with data: ??) -> Bool {

    }
}

As you can see, we have a problem here. What data do we pass into the authenticate method. For an iPhone X we will need facial scans. For an 8 we will need fingerprint scans. In the future, who knows what data we might need. How can we make this generic? Well, associated types of course!

struct iPhone8 {...}
struct iPhoneX {...}

protocol BiometricAuthenticatable {
    associatedtype BiometricData
    func authenticate(with data: BiometricData) -> Bool
}

extension iPhone8: BiometricAuthenticatable {

    typealias BiometricData = FingerprintScanData
    func authenticate(with data: BiometricData) -> Bool {
        ...
    }
}
extension iPhone10: BiometricAuthenticatable {

    typealias BiometricData = FacialScanData
    func authenticate(with data: BiometricData) -> Bool {
        ...
    }
}

Now, we can use our BiometricAuthenticatable protocol on any device so long as it defines which type of data it expects to receive. You can even make this more DRY by moving the default implementation into a protocol extension with where clauses:

struct iPhone8 {...}
struct iPhoneX {...}

protocol BiometricAuthenticatable {
    associatedtype BiometricData
    func authenticate(with data: BiometricData) -> Bool
}

extension BiometricAuthenticatable where BiometricData == FingerprintScanData {
    func authenticate(with data: BiometricData) -> Bool {
        ...
    }
}

extension BiometricAuthenticatable where BiometricData == FacialScanData {
    func authenticate(with data: BiometricData) -> Bool {
        ...
    }
}

extension iPhone8: BiometricAuthenticatable {
    typealias BiometricData = FingerprintScanData
}
extension iPhone10: BiometricAuthenticatable {
    typealias BiometricData = FacialScanData
}

Because we have moved our implementations of authenticate into protocol extensions, we now have no need to implement them in the device structs themselves. This makes adding more devices even easier!

extension iPhone8Plus: BiometricAuthenticatable {
    typealias BiometricData = FingerprintScanData
}
extension iPadX: BiometricAuthenticatable {
    typealias BiometricData = FacialScanData
}

And when we call these functions, we will now see that auto complete suggest the proper signatures. Awesome!

let iphoneX = iPhoneX()
iphoneX.authenticate(with: < xcode suggests FacialScanData>)

let iphone8 = iPhone8()
iphone8.authenticate(with: < xcode suggests FingerprintScanData>)

What is Self?

Remember our previous compiler error with equatable?

Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements

We now know what associated type requirements are. But what is that Self? And why does it have a capital S?? Well, Self is kind of similar to any old Associated type, expect it is more specific. Self refers to the type that is actually conforming to the protocol, whichever type that may be. For instance, String conforms to Equatable. So in the case where the Equatable protocol refers to Self and String is the object we are equating, Self means String. When we are equating to Ints, Self means Int. Lets take a look at the signature for == in Equatable:

public static func ==(lhs: Self, rhs: Self) -> Bool

This is exactly like using a generic or an associated type. This is essentially saying that == takes in two values of the same type Self - which can be anything that conforms to equatable, and returns a boolean. So if we write "Hello" == "Hello"then Self is a String, but when we say 25 == 25 Self is an Int. Self gives your protocols a way to have a generic reference to the conforming type. Great! Self can also be very useful for protocol extensions. For instance, because of Self, we can write awesome protocol extensions that only apply to certain types. So, lets say we want to create a protocol called Shakeable that adds the ability to shake some view. For now, we only really care about the implementation for UIViews. With Self, we can do this:

protocol Shakeable {
    func shake()
}

extension Shakeable where Self: UIView {
    func shake() {
        ...
    }
}

Now any UIView that conforms to Shakeable will get this implementation of Shakeable for free. Not only that, but because this extension constrains Self to UIView, we can actually use functions and properties of UIView in our implementation. Nice!

Why are Associated Types and Self So Constraining?

Lets get back to our original problem. Why, when we try to use Equatable as a concrete type, does the compiler through this error?

func areAllElementsEqual(_ elems: [Equatable]) -> Bool { // compiler error - Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements
    guard var lastElem = elems.first else { return false }
    for elem in elems {
        if elem != lastElem { // compiles!
            return false
        } else {
            lastElem = elem
        }
    }
    return true
}

Well, think of it this way. This code says that as long as the elements conform to Equatable, they can be apart of this array. This would mean that our array may not necessarily be homogeneous, that is, this array could potentially be a mix of Strings, Ints, Doubles, etc. So, in a magical world in which the above code actually compiles, lets follow that outcome a little farther. Say we give the following input:

areAllElementsEqual(["Hello", 1, "heterogeneous", 2.0, "array"])

Now, our function loops through and trys to equate “Hello” and 1. How would this work? Strings and Ints can never be equal. So really it doesn’t make sense for the compiler to even allow us to make this comparison in the first place. Hence, the compiler restricts protocols with Self or associated type requirements to only be used as generic constraints, not as stand alone types.

Another example of this can be easily seen with our BiometricAuthenticatable protocol. Let’s say I wanted to do the following:

let authenticatable: BiometricAuthenticatable = iPhoneX() // compiler error - Protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements

authenticatable.authenticate(???)

This example doesn’t really make sense, because we are declaring authenticatable as a generic BiometricAuthenticatable and at run time we are assigning the specific implementation iPhoneX. Because this assignment happens at runtime, the compiler has no idea what the data parameter’s type should be. Should it be FacialScanData? Or FingerprintScanData? Who knows! So all in all, it makes sense for the Swift compiler to just disallow using protocols with associated types as concrete types all together.

Conclusion

We have now explored many aspects of generics in Swift and I hope you have learned a thing or two. Generics can be a great way to keep your code safe and DRY. Whether you are creating new objects, writing functions, or defining protocols, a well placed generic can save you a lot of duplicate code and eliminate runtime bugs.

What do you think? Will you try to use generics more in the future? What ways do you use generics in your code? Do you have any questions, feedback or comments to give? I’d love to hear from you.

-Luke Street
@ldstreet

/

Playing with Protocols 2: Foundational Support

Hey all!  I'm happy to have you back, and thanks for taking an interest and reading!  If you missed part one, it can be found here.

I realize now that I never described what a protocol is in Swift in the first post, but was able to get away with it since the first post just covered design.  Allow me to rectify that right now.  According to the Apple documentation a protocol “defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.”  That protocol can then be adopted to a class, struct, or enum that will be responsible for giving the blueprints some implementation. One of the largest benefits with using protocols over classes is that you run the risk of having to update a lot of code if your architecture changes in the future.  Since nothing is implemented by the protocols themselves, the classes, structs, or enums that conform to them are less coupled.  Now that that’s out of the way and we’ve got an idea of where we want our protocols to be, let’s fire up Xcode and actually start developing!  

Side Note:  A quick update before we get started.  I renamed the fight() function from the previous post to attack().  It makes more sense when writing code to say Character A attacks Character B.  It’s basically a more descriptive term.  Now, on with the post!

Folder structure.png

I used the standard “Single Page Application” to get the app off the ground. The first thing I like to do when creating a new application is organize my files in Xcode.  To that end I created three groups to store my files; Enumerations, Protocols, and Structs.  I’ll probably add more as time and development goes on, but this is a good way to start.  

I believe it makes the most sense to start with the most abstract protocol for the application, which in our case is BasicCharacter.  Reviewing the UML diagram from the last post I know I’ll need six attributes and three functions.  To create a protocol, first create a new Swift file.  Name it whatever you’d like and Xcode will produce a file with some general boilerplate code and a single import statement.  Use the keyword ‘protocol’ and followed by the protocol’s name and you’re ready to go!  In our case it will look something like this:

import Foundation

protocol BasicCharacter {

}

Now we name all of the attributes and write out the functions.

Errors everywhere!.png

Well that’s…..sub-optimal.  There are errors everywhere!  What’s happening?  Taking it from the top, I used the ‘let’ keyword to define the name attribute.  This makes sense if I don’t want the user to have a chance to change it after it’s been set.  A character’s name should be constant.  There’s a debate that can be made that we should be able to change it in some way (people do change their names after all) but for the purposes of the game, I would rather not allow that to happen.  Xcode disagrees with me and there’s a reason for that.  If you refer to the definition of a protocol that Apple provides from the first paragraph, a protocol should have no impact on how a class, struct, or enum conforms to it.  By stating an attribute is a constant by using ‘let’, the protocol would be forcing any conforming classes to also use let.  It is still valid to set the attribute as a constant in the conforming class or struct (spoiler alert: it’s what I do).  All other errors are the same, the property should have at least a { get } and possibly a { get set } specifier.  These keywords determine whether the attribute is read or read-write.  Something to keep in mind when dealing with { get set } is that it must be settable, meaning that the attribute must be a var.  If we were to only use { get }, as is the case for name in the picture below, then when we define the property in the conforming class or struct, it can be a let.  Let’s clean this up.

All fixed!.png

 That’s much better!  Now it’s time to add the function signatures.

functions.png

No issues here (spoiler alert 2: yet).  Now we repeat this process for our other most-abstract protocols; Item and Objective.

import Foundation

protocol Item {

var strength: Int { get set }
var agility: Int { get set }
var intelligence: Int { get set }
var durability: Double { get set }
var isBroken: Bool { get set }

func breakItem() func repairItem()

}

import Foundation

protocol Objective {

var experience: Int { get }
var reward: Item! { get set }

}

Good job!  We’ve just created the foundation for the rest of the app.  Think about our design from the first post now.  Hero and Enemy both inherit from BaseCharacter and Weapon and Armor both inherit from Item.  How do we express that in our code?  It’s actually simple.  We say that the sub-protocols conform to the foundational protocols.  In the case of Hero we would have:

import Foundation

protocol Hero: BasicCharacter {

var inventory: [Item]! { get set }

func loot(theEnemy: Enemy)
func equip(theItem: Item)
func complete(theObjective: Objective)

}

And for Enemy it’d be:

import Foundation

protocol Enemy: BasicCharacter {

var loot: Item! { get set }

func flee()

}

Following suit with Weapon and Armor we get:

import Foundation

protocol Weapon: Item {

var minDamage: Int { get set }
var maxDamage: Int { get set }
var type: WeaponType { get }

}

import Foundation

protocol Armor: Item {

var value: Int { get set }
var type: ArmorType { get }

}

What you’re seeing here is an elegant and powerful idea.  Each sub-protocol will take on the responsibilities of the foundational protocol.  What this means in practice is that if I were to create a Hero struct, I wouldn’t need this:

struct HeroStruct: Hero, BasicCharacter { ... }

But rather I could do this: 

struct HeroStruct: Hero { ... }

It seems simple with the given example but the fact conforming to the terminal protocol in a waterfall-like series of other protocols will hold a class, struct, or enum responsible for all of the “methods, properties, and other requirements (to quote Apple)” laid out in the protocols before it make life easier on us as developers.  We have less of a chance to miss out on conforming to a protocol if there are fewer protocols of which to conform.  Y’all know me, the less I have to think about configuration and setup like this, the better off I am!

I had more planned for this post but it’s already gotten long.  I’ll move on to creating the structs in post three!  I have also created three more protocols that conform to Hero and three more that conform to Enemy.  I wanted to have something more concrete to play around with when writing the code.  For Hero they are; Wizard, Warrior, and Archer.  For Enemy they are; Orc, Goblin, and Android (yeah I went there).  I’ll cover these more in post three as well (I told you I had a lot planned haha).  In the meantime, see if you can write up your implementations of these.  I’d love to hear what types of attributes or functions you think each should have!  

Yours in code,

Zack

/

Having Fun with UIDynamicAnimator, Part 1

The beauty of having a blog instead of just a podcast is now, I can show you all some cool stuff that isn't as easy to explain over audio.  One obvious thing is any topic to do with views.  This particular topic is actually from a Learn Swift LA meetup that I led back in May of last year.  It came about because someone introduced me to the UIDynamicAnimator, and I found it so fun and easy to learn that I needed to show it off in the next meetup.  

Here's what we're going to do.  We're going to make an air hockey game.  This works best on an iPad, but you can totally play this on your iPhone as well.  Air hockey is a two player game, so be sure to grab  friend when you're done and totally dominate them with your superior coding and mad puck skills!  To get the most out of this post code along with me.  I'll give you step-by-step instructions all the way down.

Screen Shot 2018-04-01 at 1.59.25 PM.png

Start by creating a new Xcode iOS project.  Choose a new Single View App and click Next.

 

Let's name our project AirHockey.  Don't forget to set the Language to Swift.  We also don't need Core Data or tests for this project, so you can safely uncheck those before clicking Next.

Pick a place to save your new project and click Create.  Now we're really ready to begin.

 

Screen Shot 2018-04-01 at 2.01.55 PM.png

Now this app will work best on iPad, but it can most definitely work on iPhone as well.  So let's keep the Devices set to "Universal", but we don't want the screen to rotate at all, so only have Portrait checked.  I don't remember the earliest SDK we can use for this app, but I do know it works well with iOS 10, so let's set that as our Deployment Target.

Screen Shot 2018-04-01 at 3.00.18 PM.png

I like working with Storyboards.  This part sucks for blog posts, because there's a lot to do, but I don't want to have a million screenshots.  We're only going to add 7 UIViews to our initial ViewController, so it shouldn't be too bad.  Start by adding the center view.  It's hard to see in the screenshot below, but it's 3 pixels high, centered vertically, and spans the width of the view.  Then add the top view.  Constrain it to the edges of the Safe Area and the top of the center view.  Finally add the bottom view, and constrain it to the edges of the Safe Area and the bottom of the center view.  I made the colors red and green to make them more obvious.  We want the final color to be white like a hockey rink.

Screen Shot 2018-04-01 at 3.08.36 PM.png

Now we need to add the goals.  Like I said earlier, these work better for the iPad, but will totally still work for iPhone as well.  I'm using an iPhone layout, because it's easier to see in a blog post.  The goals are just UIViews like the other views we added.  Now this is VERY important.  These views must be subviews of the ViewController's view not subviews of the top and bottom views we added earlier.  Note the hierarchy on the left outline panel.  For sizes, I'm setting the height to 40 and the width to 200.  Feel free to set them to your preference.

Screen Shot 2018-04-01 at 3.21.58 PM.png

Finally we need to add the paddles and the puck.  Just like before, we need to have all our objects in the same view hierarchy.  Constrain your puck to the vertical and horizontal centers of the view.  For the paddles, constrain them to the horizontal center of the view and about 100 px from the top or bottom of the view respectively.  I used a size of 100x100 for my paddles and 50x50 for my puck, but you can play with that to see what works for you.  When you finish this step, run your code to make sure everything looks the way you want it to look.

Screen Shot 2018-04-01 at 3.29.51 PM.png

Next, connect outlets to all of these views, so we can reference them in our code.  For those of you who haven't done this before, with the assistant editor open, you can hold the control button, click on a view, and drag into your code.  A dialog box will appear to let you name your new outlet.

Screen Shot 2018-04-01 at 3.56.05 PM.png

Alright, now all the view setup is done, we can start playing with code.  Navigate to your ViewController class, and add this property near the top:

class ViewController: UIViewController {

    var animator: UIDynamicAnimator!
    
    ...
}

This UIDynamicAnimator is the key to making this all work.  It's pretty amazing how much power you have just by adding this little guy to your code.  To demonstrate, let's add a little gravity.  Add this to your viewDidLoad() method and run it.

override func viewDidLoad() {
    super.viewDidLoad()

    animator = UIDynamicAnimator(referenceView: view)

    let gravityBehavior = UIGravityBehavior(items: [puck])
    animator.addBehavior(gravityBehavior)
}

Your puck just fell off the screen!  Now that's interesting.  We can even control the direction and magnitude of gravity.  Add this to your code now and run it.

    let gravityBehavior = UIGravityBehavior(items: [puck])
    gravityBehavior.gravityDirection = CGVector(dx: 0, dy: -1)
    animator.addBehavior(gravityBehavior)

Now the puck flies up through the top of the screen!  So much power!!!  But it does suck that the puck leaves the screen, so let's make it stay in our view.  We'll need this for our game anyway.  Add a collision behavior.

    let collisionBehavior = UICollisionBehavior(items: [puck])
    collisionBehavior.translatesReferenceBoundsIntoBoundary = true
    animator.addBehavior(collisionBehavior)

Now the puck stops at the top of your view with a little bounce.  That's pretty nice.  We want the puck to collide with the paddles, so let's add them to this same collision behavior.

    let collisionBehavior = UICollisionBehavior(items: [puck, topPaddle, bottomPaddle])
    collisionBehavior.translatesReferenceBoundsIntoBoundary = true
    animator.addBehavior(collisionBehavior)

This is interesting.  Now the puck runs into the top paddle, but the gravity still exists, and the puck pushes the paddle to the top of the view where it stays.  This is close to what we want, but we really don't need the gravity for our game, so let's remove it.

//        let gravityBehavior = UIGravityBehavior(items: [puck])
//        gravityBehavior.gravityDirection = CGVector(dx: 0, dy: -1)
//        animator.addBehavior(gravityBehavior)
Screen Shot 2018-04-01 at 4.59.36 PM.png

What we really want is to control our paddles.  For this we need some pan gesture recognizers.  From the storyboard, add a pan gesture to the topHalf, topPaddle, bottomHalf, and bottomPaddle views.  Be sure to label them each time you add them, or it will get very confusing when we connect them to their actions.

Create a new IBAction called userPannedTopHalf() and connect both the topHalf and topPaddle pan gestures to it.  Make sure to set the type to UIPanGestureRecognizer when you create the new action.

Screen Shot 2018-04-01 at 5.02.48 PM.png

Do the same thing with the bottom pan gestures, but create an IBAction called userPannedBottomHalf.  Add this code your ViewController, and run your code.

class ViewController: UIViewController {
    ...
    var topSnapBehavior: UISnapBehavior?
    var bottomSnapBehavior: UISnapBehavior?
    ...

        @IBAction func userPannedTopHalf(_ sender: UIPanGestureRecognizer) {
        if topSnapBehavior != nil {
            animator.removeBehavior(topSnapBehavior!)
        }

        switch sender.state {
        case .began, .changed:
            topSnapBehavior = UISnapBehavior(item: topPaddle, snapTo: sender.location(in: view))
            animator.addBehavior(topSnapBehavior!)
        default:
            break
        }
    }

    @IBAction func userPannedBottomHalf(_ sender: UIPanGestureRecognizer) {
        if bottomSnapBehavior != nil {
            animator.removeBehavior(bottomSnapBehavior!)
        }

        switch sender.state {
        case .began, .changed:
            bottomSnapBehavior = UISnapBehavior(item: bottomPaddle, snapTo: sender.location(in: view))
            animator.addBehavior(bottomSnapBehavior!)
        default:
            break
        }
    }
}

Now when you move your finger in the bottomHalf of the screen, the bottom paddle snaps to your finger.  You can then use this to hit the puck.  Pretty cool, huh?  And you can do this with the top paddle as well.  You can even "throw" your paddle like Thor throws his hammer, and like his hammer, it'll come right back to you by moving your finger a little bit on your side.

This is a pretty good place to stop for this post.  You have a functioning ice rink with no need for a zamboni.  You have two functioning paddles with a puck.  (Ok, they're square, which is a little weird.)  Next time we'll make the paddles and the puck circular, enforce side rules, and add in a scoring mechanic.  Feel free to try to do these things yourself in the meantime.  Trust me, you'll learn more by exploring than by me telling you.  Until then, happy coding!

-Steve

P.S. Here the final code, so you can check your code against mine.

/

Playing with Protocols, Pt. 1: Design

Hey all!  Today I'm going to revisit a topic covered in one of our older episodes, protocols!  That episode was a fun one to prepare for, as I spent most of the week leading up to it building out a (small) game engine.  The code can be found here.  That's right, we used to have a Github that we uploaded code to for a little bit.  Maybe we'll get back to that in the future.  We actually had a misstep in that episode that we have yet to repeat since recording it.  We read nearly that entire playground.  It wasn't fun for us and we don't think it provided our listeners with good content.  I still wanted to talk about it though, and now that we've got the blog....why not do it here???  I'm envisioning the Playing with Protocols group of blog posts to cover creating a game engine using protocols, from design to implementation, using the old playground I wrote as a template.  

Before I get started on any project I like to design the parts of my system.  I view it as the foundation on which the project will be built, and in all honesty, it's one of my favorite parts of writing software.  It's a time to show off your creativity, and build something beautifully.  You can set yourself up for success if you design your project correctly.  The flip side of that is also true.  Hasty designs or ill-considered assumptions lead to flawed projects where you spend more time fixing bugs than you do implementing features, and no one wants that!  

 

Step One: Begin at the beginning

You would think this goes without saying, but in practice it can be somewhat hard to do.  Decide what you want to build, then figure out how you are going to build it.  The goal at the end of this series of posts is to have a game engine for a role-playing game (RPG).  For those who may be unfamiliar with what an RPG is, it is generally a game in which the player will have some grand objective but initially lacks the skills to complete that objective.  Sound familiar?  To me it's analogous to my coding journey.  When I first sat down to code I didn't know the difference between a stack and a queue.  When I started learning Swift I couldn't tell you how to create a dictionary, much less make a call to a backend database such as Firebase, and then parse the results.  All of this I learned with time.  Sean Allen does a great job of explaining it in his video here.  

Where does that leave us now?:  Starting is usually the hardest part of any project for me, and I don't think I'm alone in that.  The trick is to break your idea down to it's most atomic parts and then turn those into features.   What happens in an RPG?  A player will usually choose between a set of specializations for their character to be, such as Wizard, Warrior, Archer, etc.  The player will guide the character through smaller objectives while fighting enemies (or not) to collect experience.  As the character gains experience it will become stronger and be able to defeat stronger enemies and clear tougher objectives.  Repeat this process until the character is strong enough to tackle the final objective.  Some companies have made literally billions of dollars off of this model (looking at you Blizzard).  

Have we accomplished anything yet?:  It may not feel that way now, but by defining our goal even in abstract terms as above, we start to get a clearer picture of what we need to build for our project.  There will be a character, enemies, items and objectives.  Let's take a look at these individually:

Characters:

What makes a character?  Let's say our character has these attributes: a name, health, experience, strength, agility, and intelligence.  We also know that a player can choose a type for a character to be.  Of course that's not all a character is.  It would be a pretty boring game if the character sat on the screen the entire time unable to do anything!  Each character will also be associated with a group of actions.  A character can fight, heal, loot an enemy, and (hopefully not) die.  

Enemies:

We need to have some opposition!  Enemies will be of a certain type and will have a name, health, strength, agility, intelligence, and will give the player some amount of experience after they are defeated.  They too can fight and heal. In addition to those actions an enemy can also flee.  We're already starting to see similarities between our characters and the opponents that they will face.  Things are shaping up!

Items:

If a player can loot an enemy and an enemy can be looted, then we need to have items to facilitate this action.  What adventurer doesn't like a pile of glittery treasure?  Items should definitely be of more than one type, and should also have stats on them.  It feels as if things are getting complicated again, so let's break it all down one more time.  An item could be a piece of armor or a weapon.  Depending on type, it will have different stats.  

Objectives:

Objectives will have certain goals for characters to meet before they can be completed.  They will reward characters with experience and possibly an item.

Step Two: Abstractualize

I'm pretty sure that's a word.  Now we start getting into the protocol portion of the post.  Look at every possible object we've broken down so far.  Extract commonalities to the most abstract protocol and then refine from there.  Both characters and enemies have names, health, experience and basic stats.  They also share the fight, heal, and die actions.  If we create an abstract protocol that contains these traits and actions then we will be forced to define similar functionality for the structs which implement them.  Items are broken down into weapons and armor, but again, there are shared traits between them such as the types of stats present.  In the current design objectives stand on their own.

Step Three: Visualize

This is when each of the designs covered so far become more concrete.  Simply the act of getting the design out of your head and onto something visual helps you decide where to take your application.  There are plenty of times when designing a program one way of doing things may seem to make sense up until the point the ideas flow from your head and onto (possibly metaphorical) paper.  I used draw.io to create the following Unified Modeling Language (UML) diagram.  What is UML?  It's basically a picture of your program's architecture. 

Character UML:

Character UML.png

These diagrams are the blueprints of the application.  Reading these make sense once you've walked through a few them.  Each box is broken down into three sections with the topmost being the name, the middle being the attributes, and the final being the functions.  A diagram may omit the second or third section (as the Enemy diagram has done with the second section), but must always have the first.  Let's look at what we've got here.  There's an abstract protocol named BasicCharacter.  It has the attributes we mentioned earlier in the second section, with the function signatures in the third section.  This protocol is inherited by two other protocols, the Hero, and the Enemy.  In addition to the what's defined in the BasicCharacter, these two protocols will force you to build out additional functionality based on whether you adhere to the Hero or the Enemy.

Item UML:

Items.png

The item UML diagram is very similar to that of the character UML diagram.  All items will share the basic strength, agility, intelligence, durability, and isBroken traits.  An item is also responsible for breaking down and repairing.  We will have two flavors of item in our game engine, weapons and armor.  There's a need to define two protocols specific to each type of item because they will fill very specific roles.  It wouldn't make sense (in most cases) to have a weapon that also had some armor value, just as armor should not have damage attributes (again in most cases) (yes I know getting punched with a gauntlet wouldn't be enjoyable).  The final attribute in each protocol will be an enumeration I'll cover next article.

Objectives UML:

Objective.png

The final protocol I've defined is for objectives.  These are going to be straight forward in that they just hold attributes for what a player would get if he or she completed the objective.  The reward is an optional object that conforms to the Item protocol because not all objectives will have an associated reward.

What's next?

These protocols are great, but they don't do much on their own.  Literally.  There's no implementation at all.  Next up we're going to tackle writing out our protocols and creating the structs that adhere to our them.

I hope you enjoyed my first post as much as I enjoyed writing it!  Are there flaws in my design?  Most definitely!  That's part of the process and it's very important to keep it in mind.  Don't become rigid in your first design because it can (and most likely should) change.  With that being said, let me know what you think of it so far in the comments below.  These posts aren't planned ahead so you're getting an inside look at building this engine out first hand.  It will get ugly at times.  Again, that's part of the process.  There are very few (read: NONE) developers I know that can sit at a computer, fire up an IDE, and write a flawless program from start to finish.  All of the great developers do share one trait though; they absolutely love the process.  Writing code isn't as romantic as it's portrayed in pop culture.  Keep working at it and you'll become great as well.

-Zack

/

Welcome to the Fireside!!!

Hey everyone!

Welcome to the Fireside Swift blog.  This will not only be a place for us to create textual content to go along with episodes (everyone could finally SEE examples of code!) but we would like it to also be a home where you, our listener, has a chance to not only interact with us more easily but each other as well.  We're aiming to build a community here, and we can't do it without you.  Let's light the kindling and create something special.  Come along!

-Steve and Zack

/