Swift: Image Picker

A quick overview of getting an image from the camera, or the photo library.

First, set up your view in the interface builder. For this example, I'm keeping it really simple with a UIImageView and 3 buttons.

Update the UIViewController for your view to import MobileCoreServices (contains the constants required for defining what we want from the picker). Also, add support for the protocols we will need for our view controller to serve as a delegate on the picker. If you have created a new project, this will be ViewController.swift.

import UIKit
import MobileCoreServices

class ViewController: UIViewController {
 
}

extension ViewController: UIImagePickerControllerDelegate {

}

extension ViewController: UINavigationControllerDelegate {
    
}

Note that I've taken advantage of Swift's protocol extensions to keep my delegate handling code separate from the rest of my application code. This helps keeps things logically grouped and makes it easier to keep it tidy. I'm not interlacing different contexts which will make it easier to read if I come back to it months later.

Add the user interface code. We're going to get a reference to the UIImageView so we can update it. We'll also hook up actions to the buttons so we can trigger the desired behaviour.

class CameraViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    
    @IBAction func displayCamera(sender: UIButton) {
        displayImagePicker(.Camera)
    }
    
    @IBAction func savedPhotos(sender: UIButton) {
        displayImagePicker(.SavedPhotosAlbum)
    }

    @IBAction func photosLibrary(sender: UIButton) {
        displayImagePicker(.PhotoLibrary)
    }
    
    func displayImagePicker(sourceType: UIImagePickerControllerSourceType) {
        guard UIImagePickerController.isSourceTypeAvailable(sourceType) else {
            return
        }
        
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = sourceType
        imagePicker.allowsEditing = false
        imagePicker.mediaTypes = [kUTTypeImage as String]
        presentViewController(imagePicker, animated: true, completion: nil)
    }
    
    func handleImage(image: UIImage) {
        imageView.image = image
    }
}

A quick description of what's here:
@IBOutlet allows us to connect a component from Interface Builder - just display the source code side-by-side with the Interface Builder view and Ctrl+Drag to connect them. If you drag to an empty space in your code, Interface Builder will prompt you to create an @IBOutlet, or @IBAction.
@IBAction allows us to connect an action on a component in Interface Builder. In this case, Touch Up Inside to define a touch event ending (lift up) that occurred inside the relevant component. As with @IBOutlet, Ctrl+Drag to connect the Interface Builder view to the source code.

The UIImageView, imageView, is defined as a weak reference as the reference will be held for us by the view so we don't need a strong reference in our UIViewController under most circumstances. Doing so can, in fact, lead to memory problems. We don't need specific references for the buttons since we don't need to access, or change, their state.

The @IBAction prefixed functions will trigger when the relevant button is pressed. I've included the button as a parameter, though this isn't necessary for this application, as it can be useful in other cases and is included by default if you let Xcode create the method for you. These methods just call a helper with an appropriate parameter for the source we want to get an image from.

displayImagePicker(sourceType) is a method that creates, and displays, the image picker. This just lets us reuse code that we'd otherwise have to include in all 3 of our IBAction methods since the only change, in this example, is the sourceType. Other than the image picker, the only notable addition is the use of a guard-statement to check if the source type is available. For this I'm just returning if it's not, but a more complete application might display an error message here.

handleImage(image) takes a UIImage as a parameter and updates the imageView to display it. This is nice for a test but of minimal use otherwise.

This code will run but will not do much because we don't currently handle the image retrieval. Nothing is calling the handleImage(image) method yet. Update the UIImagePickerControllerDelegate protocol extension like so:

extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        dismissViewControllerAnimated(true, completion: nil)
        let mediaType = info[UIImagePickerControllerMediaType] as! String
        if mediaType == kUTTypeImage as String {
            let image = info[UIImagePickerControllerOriginalImage] as! UIImage
            handleImage(image)
        }
    }
}

All we're doing here is handling the UIImagePickerController being dismissed and retrieving the image, if the media type is an image. It should be since we've requested that only image types be allowed but I've included the check in case you want to extend this to handle video in the future.

Note that, whilst we do need to declare that we support the UINavigationControllerDelegate protocol to assign our view controller as the delegate of the image picker, we don't need to handle any of the callbacks so we can leave this blank for now.

Run the app. It's better on a real device since the simulator doesn't support the camera, but the photo library should be accessible on both (privacy restrictions permitting). 

Swift: Initialising a 2D Array

I have a struct called Tile, which has (for now) a position defined as a tuple:

struct Tile {
    let pos: (Int, Int)
}

And a class called Board, which has a 2D array of Tile objects:

class Board {
    let tiles: [[Tile]]
    
    init() {
        var tilesArray = [[Tile]]()
        for row in 0..<Board.rows {
            var rowTiles = [Tile]()
            for column in 0..<Board.columns {
                let tile = Tile(pos:(column, row))
                rowTiles.append(tile)
            }
            tilesArray.append(rowTiles)
        }
        
        tiles = tilesArray      
    }
}

This works, though it feels a little messy... I'll have to come back and look at this again.

Xcode 7 and Swift 2: Unit Testing (again)

Some follow up from creating a new project and adding tests.

This turned out to be important...

This turned out to be important...

I hadn't really noticed in the last one but I hadn't added the new classes to the test target, as I would under Obj-C. In Swift 2 there's a new @testable keyword. I found it blogged by Natasha the Robot when I started looking to find out why I wasn't seeing any code coverage showing up for my classes.

Then I started wondering why I was getting Undefined Symbol errors. I could resolve them by including the classes, but then I wouldn't get coverage and everything I saw on @testable assured me I didn't need to include them. Finally, I remembered I'd been getting a bit click happy earlier. I'd disabled Allow testing Host Application APIs.

One checkbox later and I'm a happy camper...

Okay, not a lot done tonight but I feel like a few pieces fell into place.

NSInvocation - Calling Blocks

Because I always forget.

    id mockView = OCMClassMock([UIView class]);

    [[[[mockView stub] ignoringNonObjectArgs] andDo:^(NSInvocation *invocation) {
        __block void (^animationBlock)(void);
        [invocation getArgument:&animationBlock atIndex:3];
        animationBlock();
        __block void (^completionBlock)(BOOL);
        [invocation getArgument:&completionBlock atIndex:4];
        completionBlock(YES);
        
    }] animateWithDuration:0 animations:OCMOCK_ANY completion:OCMOCK_ANY];

Unity - Generating Builds

Adding the below code to Assets/Editor will add an entry to the menu bar that allows me to generate two builds automatically. Since they're also placed in a folder with the day's date, I also get build histories for the work done. For GameJams this is ideal as I'll usually only get a small amount of time on an evening to work on these so I'm not doing much more (and I could always use a more precise timestamp if needed). This is basic but so easy to automate and a nice little time saver that I thought I'd share.

using UnityEditor;
using System.Diagnostics;
using System;

public class JamBuilds 
{
    [MenuItem("Build/Jam Builds")]
    public static void BuildGame () {
        // Get filename.
        string path = EditorUtility.SaveFolderPanel("Choose Location of Built Game", "", "");
        string[] levels = new string[] {"Assets/Scenes/Test.unity", "Assets/Scenes/Finale.unity"};
        string projectName = PlayerSettings.productName;

        string date = DateTime.Now.ToString("/yyyy-MM-dd");

        // Build player.
        BuildPipeline.BuildPlayer(levels, path + date + "/" + projectName + ".exe", BuildTarget.StandaloneWindows, BuildOptions.None);

        // Build player.
        BuildPipeline.BuildPlayer(levels, path + date + "/WebPlayer", BuildTarget.WebPlayer, BuildOptions.None);

    }
}

And There Went My Resolve

Sometime around doing my first Game Jam I stopped posting regular updates. I'm not entirely surprised but I am a little disappointed in myself.  Anyway, since the last post was at the start of this month, I am going to try and get a couple more in, if only because I've managed another Game Jam release and a quick Unity port of an earlier game I made to talk about.

And for kicks:

In all honesty, the alcohol probably belongs at the start, as well as the finish ;)

Xcode Plugins

Install the Alcatraz (http://alcatraz.io) package manager to get these.  

https://github.com/neonichu/BBUFullIssueNavigator
Shows the whole error/warning in the issue navigator instead of a single line.

https://github.com/yuhua-chen/MCLog
Allows you to filter the console by a regular expression. 

https://github.com/markohlebar/Peckham
Add imports from anywhere in the code base - press Cmd+Ctrl+P to pop up a window which has autocompletion for your headers. 


https://github.com/onevcat/VVDocumenter-Xcode
Fill in a quick documentation template.


https://github.com/kinwahlai/XcodeRefactoringPlus
Additional refactoring tools. Still not as full-featured as some IDEs but it's a case where every little helps.

Refining Terrain

Tweaking values - went a little high on the mountain frequency.

Refining it down. Kind of fun to jump around right until you fall to the bottom ;)

That's more like it!

Tools - Unity

It took a while but I think I'm finally feeling comfortable working in Unity.The other night I built a minimum viable prototype of one of my iOS games over the course over just a couple of hours. I feel like I'm still learning the flow of the engine, particularly with regards to threading, but there's a lot of power and potential to be tapped and getting started with it is easy. That said, I do miss the more advanced debugging tools I get with something like IntelliJ, or Xcode. And MonoDevelop is pretty awful ;)