Mario

☝️ NO submission is required for labs

MarioKart - Gestures & Animations

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
 
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
 
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Overview

Tired of boring button-centric UI? Wellin iOS it's easy to implement interactive gestures and fun animations to give your UI some well deserved pop! In this lab you'll build an app that allows users to interact with characters from the iconic video game, Mario Kart, panning, scaling, rotating and then sending them zooming off the screen! 🏎

User Story Tiers

The user stories for this lab are split up into 3 tiers. Tier 1 stories will introduce the core concepts of working with gestures and animations. Your goal should be to get through Tier 1 stories during your in-class lab time.

After completing Tier 1 stories you'll be able to

  1. Use gestures to trigger events.
  2. Use gestures to move and transform views.
  3. Use animations to transition views between various positions and transformations.

Tier 2 & 3 stories build on the core concepts from tier 1 and yield a more complete and nuanced app. Try out Tier 2-3 outside of class if you really find gestures & animations intriguing or go back to them later if you want to include some of these features in your group project app.

🛠 Let's Get Building - Tier 1 Stories (in-class)

1. User can move karts around the screen using a pan gesture.

In this user story, we'll leverage a pan gesture recognizer and it's location property to move around the position of our karts.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  1. Add the image assets to your project

    1. Download the MarioKart Image Assets: @[[assets/marioKart_assets.zip]]
    2. Drag the app_icon.png to the Assets.xcassets -> AppIcon -> iPhone App @2x
      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
    3. Drag the kart_[x]@2x.png images and background@2x.png image you downloaded to your Assets.xcassets folder.

      The @2x in the image file name helps Xcode place the file in the correct resolution slot automatically.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  2. Layout your views

    1. Access the Media Library and drag the background image view and all kart image views onto your view controller.

      Access the Media Library by long clicking on the Object Library icon (see gif below) or use the quick key: command + shift + m

    2. Re-size image views and set the content mode as needed: background -> Aspect Fill and karts -> Aspect Fit.

      You can duplicate views by holding option while you click and drag.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  3. Add pan gesture recognizers for kart image views.

    1. Access the Object Library and search for a pan gesture recognizer.
    2. Drag a pan gesture recognizer to one of the kart image views by dragging it from the Object Library and placing it on a kart in the storyboard.
      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
  4. Create and connect actions for your pan gesture recognizers.

    Creating an action will trigger a method to be called anytime your gesture recognizer recognizes a gesture.

    1. Create an action by control + draging from a gesture recognizer to your view controller swift file to create an action and associated function. You can name the function something like: didPanKartView

      ⚠️ Drag from the gesture recognizer listed in the Document Outline, NOT from the image view in the storyboard. (See example below)

      ⚠️ Make sure you set the type to UIPanGestureRecognizer when creating the action. (See example below)

    2. Connect actions from the remaining gesture recognizers by control + draging from from each one to the same function you created in the first action.

      Connecting all of the gesture recognizers to a single function allows us to reuse our pan logic for each kart view. This is especially useful if we want to add more karts in the future.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  5. Code the logic to move the kart when it's panned.

    1. Access the location property of the pan gesture recognizer.

      ​​​​​​let location = sender.location(in: view)
      

      ^^^
      Where should I write this code?
      ^^^
      Any code you want to run during a panning event should be in the body of the function (action) you created for the gesture recognizer.
      ^^^
      ^^^
      What's sender?
      ^^^
      When a gesture recognizer is triggered and calls it's associated function (action), it includes itself as the sender. When you reference the sender in the body of the function, you are referencing the specific gesture recognizer that was triggered. This is how you access properties of the gesture recognizer like it's location on the screen as well as the view it's attached to.
      ^^^
      ^^^
      What's location?
      ^^^
      location is a property of pan gesture recognizer's that tells us where the the user has panned in some area that we specify. In this case, it's the location in reference to the entire screen , aka the view. Positions of views are described using a data structure called CGPoint, which consists of an x and y coordinates.
      ^^^
      ^^^
      What's view?
      ^^^
      All view controllers come with a root view called view at the top of the view hierarchy. This is the main view that we are adding all of our other views into. In the above line, we are asking for the pan gestures current location within the root view.
      ^^^

    2. Print the current location returned from the gesture recognizer.

      ​​​​​​print("Location: x: \(location.x), y: \(location.y)")
      

      📲 RUN YOUR APP and pan on each kart. You should see the position of the gesture recognizer printed out in the console as you pan your finger.



      Notice how

      1. Panning on any of the karts calls our panning method.
      2. The panning method is called continuously during a panning event.
      3. The kart image view don't move yetwe'll fix that with one line of code in the next step!

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

    3. Access the view of the kart that was panned.

      ​​​​​​let kartView = sender.view!
      

      Each gesture recognizer knows the view it's attached to. We can ask the gesture recognizer (sender) for it's view in order to access the specific view that was panned (i.e. which kart image view).

      • 💡 We're forcefully unwrapping the view property of the sender using a ! to avoid having to continuously account for it as an optional value. In our case, it's safe to do so since we can be assured that anyone calling this method will have a view attached and not be nil.
    4. Set the kart view's position to the current position of the gesture recognizer.

      ​​​​​​kartView.center = location
      

      What's center - All views have a center property which describes the point of their position. Like the position property of the pan gesture recognizer, the center property is a CGPoint with values for x and y coordinates. The position of the center is in reference to the view that contains the view, this is called the super view.

      📲 RUN YOUR APP and see if you can move your kart!

      • 💡 Panning is really jerky when I run the simulator on my computer so for smooth motion (as seen in the gif below) I prefer to run the app on an actual device.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

2. User can adjust the size of a cart using a pinch gesture.

Most of the concepts you applied to get the karts panning will be used in a similar way to scale the karts using a pinch gesture. The main difference is that we will be referencing the pinch gesture's scale property to scale our karts up and down.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  1. Add pinch gesture recognizers to kart views.

    1. Access the Object Library
    2. Search for pinch gesture recognizer
    3. Drag a pinch gesture recognizer to each kart view.
      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  2. Create an action for a pinch gesture recognizer and connect the remaining.

    1. control + drag from a pinch gesture recognizer in the Document Outline to create an action in your view controller swift file.
    2. Name it something like, didPinchKartView
    3. Set the type to: UIPinchGestureRecognizer
    4. Connect actions from the remaining pinch gesture recognizers by ctrl + dragging them each to the same action you created for the first pinch gesture recognizer.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  3. Access the scale property of the gesture recognizer that was pinched.

    ​​​let scale = sender.scale
    

    Similar to the pan gesture recognizer's location property, pinch gesture recognizers have a scale property that corresponds to the size of the user's pinch.

  4. Print the scale value to the console

    ​​​print("scale: \(scale)")
    

    How do you pinch on the simulator?

    • Hold down the option key and you'll see two gray circles appear. Those represent the user's fingers.

    • Move the cursor while continuing to hold the option key until the circles are close together.

    Now, Additionally hold down the shift key and move the two circles over the object you want to pinch.

    • Release the shift key, while continuing to hold the option key, click on the object you want to pan and (while continuing to hold the click) move the cursor to pinch in and out.

    📲 RUN YOUR APP and pinch on each kart. You should see the pinch value of the gesture recognizer printed out in the console as you pinch.
    Notice how

    • Pinching on any of the karts calls our pinching function.

    • The pinching function is called continuously during a panning event.

    • Wherever the pinching starts corresponds to a scale value of 1

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  5. Access the view of the kart that was panned.

    ​​​let kartView = sender.view!
    
  6. Adjust the scale of the kart view using the scale from the pinch gesture recognizer.

    ​​​kartView.transform = CGAffineTransform(scaleX: scale, y: scale)
    

    All views have a transform property which, among other things, allows you to modify the view's scale rotation and translation. The transform property is of type CGAffineTransform, which isn't really too important for us besides helping us navigate to handy constructors to make a new transform with whatever modifications we'd like, such as the scale. In the above line, we create the transform with the scale value we get from our pinch gesture recognizer. We'll plug the scale value in for both x and y to get a uniform scale in both width and height.

    📲 RUN YOUR APP and pinch to scale your karts up and down!

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

3. User can rotate a cart using a rotation gesture.

Rotating the kart using a rotation gesture is going to be almost identical to scaling using a pinch. By this point you're really getting the hang of gestures so this should be a synch!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  1. Add rotation gesture recognizers to kart views.

    1. Access the Object Library
    2. Search for rotation gesture recognizer
    3. Drag a rotation gesture recognizer to each kart view.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  2. Create an action for a rotation gesture recognizer and connect the remaining.

    1. control + drag from a rotation gesture recognizer in the Document Outline to create an action in your view controller swift file.
    2. Name it something like, didRotateKartView
    3. Set the type to: UIRotationGestureRecognizer
    4. Connect actions from the remaining rotation gesture recognizers by ctrl + dragging them each to the same action you created for the first.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  3. Access the rotation property of the gesture recognizer that was rotated.

    ​​​let rotation = sender.rotation
    

    Similar to the pinch gesture recognizer's scale property, rotation gesture recognizers have a rotation property that corresponds to the amount of rotation in the user's gesture.

  4. Print the rotation value to the console

    ​​​print("rotation: \(rotation)")
    

    📲 RUN YOUR APP and rotate on each kart. You should see the rotate value of the gesture recognizer printed out in the console as you rotate.

    • As with all gestures, an actual device is the preferred way to test.

    • When using the simulator, the rotation gesture works similar to the pinch gesture, only instead of moving the circles (fingers) in and out, you're moving them in a circular motion.

    • Our current setup only allows for one gesture recognizer to work at a time. So, if you make a pinch motion before your rotation, the pinch gesture recognizer will claim the gesture event and the rotation gesture will not be triggered.

    • The rotation values don't seem to be in degrees 🤔 They're notthey're in radian! Silly engineers🤓

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  5. Access the view of the kart that was panned.

    ​​​let kartView = sender.view!
    
  6. Adjust the rotation of the kart view using the rotation from the pinch gesture recognizer.

    ​​​kartView.transform = CGAffineTransform(rotationAngle: rotation)
    

    Similar to the approach we used to modify the scale, we'll create a new transform using one of CGAffineTransforms handy constructors which takes an angle (in radian). We'll then set the transform property of the view to our rotated transform to rotate the view.

    📲 RUN YOUR APP and rotate your karts around and around!

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

4. User can double tap a kart to make it race (animate) off the screen.

This story will incorporate view animations that will be triggered using a tap gesture recognizer. Incorporating the tap gesture will be almost identical to the last user stories.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  1. Add tap gesture recognizers to kart views.

    1. Access the Object Library
    2. Search for tap gesture recognizer
    3. Drag a tap gesture recognizer to each kart view.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  2. Create an action for a tap gesture recognizer and connect the remaining.

    1. control + drag from a tap gesture recognizer in the Document Outline to create an action in your view controller swift file.
    2. Name it something like, didTapKartView
    3. Set the type to: UITapGestureRecognizer
    4. Connect actions from the remaining tap gesture recognizers by ctrl + dragging them each to the same action you created for the first pinch gesture recognizer.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  3. Set the number of taps required to 2.

    Tap gesture recognizers can be configured to respond to different numbers of taps. You can also configure the number of touches which is how many fingers the user is required to use during the gesture.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  4. Test the tap gesture recognizer.

    ​​​print("Double tap recognized")
    

    📲 RUN YOUR APP and double tap on each kart. You should see the test statement print out in the console.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  5. Access the view of the kart that was panned.

    ​​​let kartView = sender.view!
    
  6. Test moving the kart's position

    ​​​kartView.center.x += 50
    

    The karts move 50pts on the x-axis, however the movement is more like teleportation then smooth motion. We'll fix that next by using a view animation method.

    📲 RUN YOUR APP and see if the karts move!

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  7. Animate the movement of the kart's position

    View animation is a breeze using one of several animation methods available in the UIView class. We'll start with the simplest version which allows you to set the duration of the animation and set the end state of the view your animating.

    • 💡 UIView animation methods are asynchronous so code in your app will continue to run even while the animation is in process.
    1. Set up the beginning state of your view before calling the animation method. (In our case this is just where the kart already is so we don't need to specify further)
    2. Call the animation method, inputting the time duration (in seconds) you want the animation to take.
    3. Use tab to access the various input values of the animation method.
    4. Press return when the () -> Void closure is highlighted to expand it and reveal it's body.
    5. Enter the end values for the view you're animating
    6. In the body of the closure, specify the end state of your view animation. (In our case, this is the position we want the kart finish at)
    ​​​UIView.animate(withDuration: 0.8) {
    ​​​   // Closure body
    ​​​   kartView.center.x += 50
    ​​​}
    

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    📲 RUN YOUR APP and test out your animation!

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  8. Tune your race animation!

    Now that you can animate your karts, it's up to you to tune the values to get the perfect race effect

    1. To race the kart off the screen, you'll want to move your kart by a larger amount.
    2. Change the speed of your kart by adjusting the value of the animation's duration.
    ​​​UIView.animate(withDuration: 0.6) {
    ​​​    kartView.center.x += 400
    ​​​}
    

    📲 RUN YOUR APP and your off to the races! 🏎

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

5. User can long press the background to reset the karts.

Our app has come a long way! We can move, scale, rotate and race our karts off the screenthe only problem is getting them back. In this final tier 1 user story, we'll add a long press gesture to trigger a kart reset.

  1. Store the starting position of the karts.

    In order to reset the karts to their original position, we'll need to know where to reset them to. We can store the position of the karts when our app first loads for reference.

    1. Create outlets for each kart view.
      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

    2. Declare variables to store each kart's starting point.

      We'll want to access these properties in several places in our app, so declare them in a broad scope, i.e. in the same place we created our outlets.

      ​​​​​​var startingPointKartView0 = CGPoint()
      ​​​​​​var startingPointKartView1 = CGPoint()
      ​​​​​​var startingPointKartView2 = CGPoint()
      
    3. Store each kart's starting point when the app loads.

      The viewDidLoad method is a great place for any initial setup you need to do before your view controller is presented. As the name suggests, this method is called once all of the view controller's views have been loaded, so it's safe to reference properties from our kart views.

      ​​​​​​startingPointKartView0 = kartView0.center
      ​​​​​​startingPointKartView1 = kartView1.center
      ​​​​​​startingPointKartView2 = kartView2.center
      
  2. Add a long press gesture recognizer to the background image view.

    1. Access the Object Library
    2. Search for long press gesture recognizer
    3. Drag a long press gesture recognizer to each kart view.

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  3. Create an action for the long press gesture recognizer.

    1. control + drag from the long press gesture recognizer in the Document Outline to create an action in your view controller swift file.
    2. Name it something like, didLongPressBackground
    3. Set the type to: UILongPressGestureRecognizer

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  4. Code the logic to reset the kart positions

    ​​​kartView0.center = startingPointKartView0
    ​​​kartView1.center = startingPointKartView1
    ​​​kartView2.center = startingPointKartView2
    

    📲 RUN YOUR APP and see if you can long press to reset your karts.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  5. Animate the resetting of karts.

    The current resetting of the kart's is bit abrupt. Let's wrap the resetting logic in a view animation method to smooth it out.

    1. Cut and paste your previous kart view center updates inside your view animation method's closure..you'll notice some errors

      🛑 Reference to property startingPointKartView0 in closure requires explicit self. to make capture semantics explicitInsert self.

    2. Go ahead and click the Fix button in the error popup window, or add self. before each object yourself.

      The requirement of self in this case has to do with unique properties of closures in Swift and is not important for our purposes at this point.



      All you need to know is

      Anytime you are working with animations and you get an error instructing you to add self.JUST DO IT! 👟

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

      ​​​​​​UIView.animate(withDuration: 0.8) {
      ​​​​​​      self.kartView0.center = self.startingPointKartView0
      ​​​​​​      self.kartView1.center = self.startingPointKartView1
      ​​​​​​      self.kartView2.center = self.startingPointKartView2
      ​​​​​​}
      

    📲 RUN YOUR APP to see the karts animate as they reset their positions.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  6. Reset karts to their unmodified states

    The karts reset to their starting positions just fine, however their transforms are not being reset which is leading to odd behavior if a user has scaled or rotated a kart.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    To reset a transform, we just need to create a new unmodified transform and assign it to the view we want to reset, which in this case is our kart views. You can create an unmodified transform using the transform identity property.

    ​​​self.kartView0.transform = CGAffineTransform.identity
    ​​​self.kartView1.transform = CGAffineTransform.identity
    ​​​self.kartView2.transform = CGAffineTransform.identity
    

    📲 RUN YOUR APP and see if scaled or rotated karts animate back to their unmodified states.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  • Tier 2 - (Coming Soon)
    1. User can use pinch and rotation gestures simultaneously.
    2. While panning, karts slightly scale up and back down to simulate being picked up and put back down.
    3. When a user double taps a kart it
      1. Animates backwards slightly before racing off to simulate winding up.
      2. Pops a wheelie by rotating up and back down as it races off.
      3. After finishing racing off the screen, the kart fades back in it's original position.
    4. User can triple tap the background to make all karts on the track zoom (animate) off at different speeds.
  • Tier 3 - (Coming Soon)
    1. When a user triple taps to initiate a race sequence, a character with a stop light floats down, animates through the lights (gif sequence) ending on green to signal the race. The karts then go racing off.
    2. In a race sequence, each kart races off at different speeds and the winner is presented in a winner card that drops in from the top of the screen.
    3. In the winner card, the winner is shown in an animated gif sequence.
    4. The user can tap or pan the winner card to dismiss the card and return to a reset version of the game.
    5. After a race sequence, the karts drive into position from off the left side of the screen.

Appendix

Tier 1 Topics

  1. Assets
    1. Adding images to Assets folder
    2. Adding images from Media Library to Storyboard
  2. Gesture Recognizers
    1. Objects
      • Pan, Pinch, Rotation, Tap, Long Press
    2. Actions
      • Creating gesture actions in IB, working with the sender
    3. Properties
      • Location, rotation, scale
    4. States
      • Began
  3. View Animations
    1. Working with view animation methods.
      • Asynchronous execution
    2. Initial & destination states of animated views.
  4. View Properties
    1. Resizing views in IB
    2. Adjusting view hierarchy in IB
    3. Content Modes
      • Aspect Fit
    4. Transform
      • Rotation, scale, identity
  5. Simulator
    1. Working with gestures

Tier 2-3 Topics

  1. Gesture Recognizers
    1. Properties
      • Translation
    2. States
      • changed, ended
    3. Delegate
      • Setting gesture delegate in IB, delegate methods
  2. View Animations
    1. Working with view animation methods.
      • completion handlers, animation settings
    2. Working with animated gifs
  3. View Properties
    1. View hierarchy
    2. Subviews
  4. Swift
    1. Outlet collections
    2. Iterating through collections
      • Accessing item index while iterating
    3. Generating random numbers