Adding IBInspectable to a superclass in Swift

Adding IBInspectable to a UICollectionViewCell subclass

One very useful feature I find is to add a IBInspectable background image to my views. In an entertainment app I’m currently building there is a designable cell that looks like this:

@IBDesignable
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}

what’s great about this is it gives me a very easy way to set a background image on my TrailerCollectionViewCell. It shows right up in my storyboards so I can easily set it to my “play” icon graphic.

IBInspectable in Xcode 7

Notice on the top-right of the attributes inspector it adds a “Bg Image” dropdown. When this is changed the didSet method above is triggered and it updates the view inside of Xcode, and when the iOS app runs. This is happening because the decoding from interface builder will also trigger didSet in the same fashion that interface builder does.

What’s not so handy about this approach is that I have two other types of CollectionViewCell subclasses that need similar functionality. So, I have these three classes inherit from one superclass that implements the functionality.

import Foundation
import UIKit
 
class MediaCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    var imgView = UIImageView()
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}
 
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
}
 
class ReviewCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var ratingLabel: UILabel!
}
 
class PlaythroughCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBOutlet weak var ratingLabel: UILabel!
}

It doesn’t work!

Here’s the problem though: The field disappears in my storyboard!

I spent some time debugging this issue, and found that I could work around it by overriding the bgImage variable in my subclasses, but it was not neccessary to re-implement anything. Success!

The fix

Just adding this line did the trick:

@IBInspectable override var bgImage: UIImage! { didSet {} }

So now my complete file looks like this:

import Foundation
import UIKit
 
class MediaCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    var imgView = UIImageView()
    @IBInspectable weak var bgImage: UIImage! {
        didSet {
            imgView.frame = self.bounds
            self.addSubview(imgView)
            imgView.image = bgImage
            imgView.contentMode  = UIViewContentMode.Center
            self.sendSubviewToBack(imgView)
        }
    }
}
 
class TrailerCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}
 
class ReviewCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var ratingLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}
 
class PlaythroughCollectionViewCell: MediaCollectionViewCell {
    @IBOutlet weak var lengthLabel: UILabel!
    @IBOutlet weak var ratingLabel: UILabel!
    @IBInspectable override var bgImage: UIImage! { didSet {} }
}

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Being Swifty with Collection View and Table View Cells

Here’s a common scenario: You have a table view or collection view that has a variety of different types of content. You want to display varying cells based on these types of content, and they’re all mixed within a single section. Pardon the stand-in art, but it looks roughly like this:

In the Objective-C world, it was typical to just use an NSArray to hold whatever records your collection view was going to be using as a data source, and then for each element check what class it is before picking a cell. This case seems particularly not Swifty these days.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"identifier" forIndexPath:indexPath];
    id record = self.records[indexPath.row];
    if([record isKindOfClass:[PlaythroughItem class]]) {
        // ...
    }
    else if([record isKindOfClass:[ReviewItem class]]) {
        // ...
    }
    else if([record isKindOfClass:[TrailerItem class]]) {
        // ...
    }
    return cell;
}

shudder

Okay so that’s not the most type-safe approach, although it’s surprisingly common in Obj-C iOS code. As a better alternative in Swift, we can use enum cases for the different item types, and perform lookups of the items themeselves as needed. Let’s look at an example.

Example

In an entertainment app I’m working on I’ve got a few types of cells for the types of news items that come in:

enum NewsItem {
  case Trailer(index: Int)
  case Review(index: Int)
  case Playthrough(index: Int)
}

The index is just a way to keep track of which item this it supposed to represent in the database. We take this approach to keep the amount of data needed to produce the collection view down. We don’t need all the associated data with every video to be present when putting together a collection view, we just need the info on what cell is tapped, after it is tapped.

Let’s say we have a simple collection view that shows one of these three and picks a custom cell for each. In a Swift file NewsFeed.swift I have that acts as the dataSource of my collection view for the main news view. Of particular interest is the cellForItemAtIndexPath method, which runs the NewsItem record through a switch and produces the correct type of cell, with the relevant information populated:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let record = records[indexPath.row]
    switch(record) {
    case .Playthrough(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("PlaythroughCell", forIndexPath: indexPath) as! PlaythroughCollectionViewCell
        let playthrough = MediaDB.playthroughAtIndex(index)
        cell.titleLabel.text = playthrough.title
        cell.lengthLabel.text = playthrough.length.prettyTime
        return cell
    case .Review(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ReviewCell", forIndexPath: indexPath) as! ReviewCollectionViewCell
        let review = MediaDB.reviewAtIndex(index)
        cell.ratingLabel.text = "\(review.rating) out of 10"
        cell.titleLabel.text = review.title
        return cell
    case .Trailer(let index):
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrailerCell", forIndexPath: indexPath) as! TrailerCollectionViewCell
        let trailer = MediaDB.trailerAtIndex(index)
        cell.titleLabel.text = trailer.title
        cell.lengthLabel.text = trailer.length.prettyTime
        return cell
    }
}

This code works well enough, record is of type NewsItem which can be one of three cases for the different news items we support:

enum NewsItem {
  case Trailer(index: Int)
  case Review(index: Int)
  case Playthrough(index: Int)
}

The associated index value is so that we can find the individual item in the DB when the collection view wants to display a cell.

Something about this code didn’t sit right with me though. I felt that too much of the code was boilerplate; in particular the switch felt bulky and like it had too much work being done inside each case.

But what if I created a protocol for any data source that could be presented as a collection view cell? It would change on a view-by-view basis so I don’t actually want this in my model.. but I do like having it on these particular CollectionViewCell subclasses.

So, I created a protocol called NewsCellPresentable, which I can adhere to in extensions with my custom collection view cells:

protocol NewsCellPresentable {
    func configureForIndex(index: Int)
}
extension PlaythroughCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let playthrough = MediaDB.playthroughAtIndex(index)
        self.titleLabel.text = playthrough.title
        self.lengthLabel.text = playthrough.length.prettyTime
    }
}
extension ReviewCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let review = MediaDB.reviewAtIndex(index)
        self.titleLabel.text = review.title
        self.ratingLabel.text = "\(review.rating) out of 10"
    }
}
extension TrailerCollectionViewCell: NewsCellPresentable {
    func configureForIndex(index: Int) {
        let trailer = MediaDB.trailerAtIndex(index)
        self.titleLabel.text = trailer.title
        self.lengthLabel.text = trailer.length.prettyTime
    }
}

This feels much cleaner already. Now I can go back to my cellForItemAtIndexPath method and trim it down to just the following:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let record = records[indexPath.row]
    var cell: NewsCellPresentable
    switch(record) {
    case .Playthrough(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("PlaythroughCell", forIndexPath: indexPath) as! PlaythroughCollectionViewCell
        cell.configureForIndex(index)
    case .Review(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("ReviewCell", forIndexPath: indexPath) as! ReviewCollectionViewCell
        cell.configureForIndex(index)
    case .Trailer(let index):
        cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrailerCell", forIndexPath: indexPath) as! TrailerCollectionViewCell
        cell.configureForIndex(index)
    }
    return (cell as! MediaCollectionViewCell)
}

What do you think? Is this a cleaner approach? Let me know if you have a different method in the comment, or let me know on Twitter. My username is @jquave.

P.S.

If you want to try this out yourself and don’t have the same DB layer as me… guess what? Neither do I! You can easily stub this out like this:

class MediaDB {
    class func titleForRecord(index: Int) -> String {
        return "Title!!"
    }
    class func trailerAtIndex(index: Int) -> Trailer {
        return Trailer()
    }
    class func reviewAtIndex(index: Int) -> Review {
        return Review()
    }
    class func playthroughAtIndex(index: Int) -> Playthrough {
        return Playthrough()
    }
}
struct Trailer {
    let title = "Trailer Title"
    let length = 190
}
struct Review {
    let title = "Review Title"
    let rating = 4
}
struct Playthrough {
    let title = "Playthrough Title"
    let length = 9365
}
enum NewsItem {
    case Trailer(index: Int)
    case Review(index: Int)
    case Playthrough(index: Int)
}

Personally I always stub things out with static values before I do the work of integrating with a backend service or whatever data provider is needed. This makes it much easier to iterate.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Developing tvOS Apps for Apple TV [Part 2]

Looking for some help building your Apple TV tvOS App? I’m available for consulting and development, contact me.

This is part 2 of the tvOS tutorial. If you haven’t gone through part 1 yet, I suggest you run through that first.

Adding Interactivity

In the first section we created a simple TVML document with a few buttons. It looked something like this:

<document>
    <alertTemplate>
        <title>Hello tvOS!</title>
        <button>
            <text>A Button</text>
        </button>
        <button>
            <text>A Second Button</text>
        </button>
    </alertTemplate>
</document>

This is an alert with a few buttons, and they don’t do anything. It’s also rather specific and hard-coded, so maybe what would be better is to generate the XML on the fly. We can do this fairly easily in JS. Let’s add a new function to our main.js file that will encapsulate this alert in to a simpler alert with just an OK button.

function alert(str) {
  var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <alertTemplate>
      <title>Hey Listen!</title>
      <description>${str}</description>
      <button>
        <text>OK</text>
      </button>
    </alertTemplate>
  </document>`
  var parser = new DOMParser();
  var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");
  navigationDocument.presentModal(alertDOMElement);
}

What we’re doing here is creating a string called alertXMLString that contains the TVML contents of a simple alert template with just 1 button. However for the description we’re using the TVJS string concatenation ${variable} to inject the value of str.

Next, we create a new DOMParser object that converts this string in to an actual XML DOM element.

Finally, we can present the DOM element modally using the presentModal method of the navigationDocument, a globally defined variable that will always contain the root navigation document.

Now, in our onLaunch function, let’s remove the code we had from before and simply call an alert…

App.onLaunch = function(options) {
    alert("Hello!");
}

tvOS Alert View

Run the app and you’ll see a cool tvOS alert saying “Hello!” However, clicking OK does nothing. So how do we handle event’s such as touch?

Basically, if you want to stay in JavaScript and TVML, you will want to add an event listener to the DOM element. So for example, we could add a second argument to the alert function, so that we can pass in a function that is called when the OK button sends the event for being “selected”. We’ll add this argument and call it doneCallback. To add the event listener, we can simply do so like this:

alertDOMElement.addEventListener("select", function() { doneCallback }, false);

So after updating the entire function, it should look like this:

function alert(str, doneCallback) {
  var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <alertTemplate>
      <title>Hey Listen!</title>
      <description>${str}</description>
      <button>
        <text>OK</text>
      </button>
    </alertTemplate>
  </document>`
  var parser = new DOMParser();
  var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");
  alertDOMElement.addEventListener("select", doneCallback, false);
  navigationDocument.presentModal(alertDOMElement);
}

Now, we can modify our original onLaunch function to add a callback function that will present a TVML screen. Before we do that, let’s also add a function called getDocumentContents which similarly implements a callback function when loading is done, which passes in the XMLHttpRequest object’s response to the callbacks only argument. This allows us to more easily load in various types of TVML files.

function getDocumentContents(url, loadCallback) {
  var templateXHR = new XMLHttpRequest();
  templateXHR.responseType = "document";
  templateXHR.addEventListener("load", function() { loadCallback(templateXHR) }, false);
  templateXHR.open("GET", url, true);
  templateXHR.send();
  return templateXHR;
}

This is nearly the same code as the getDocument method we defined earlier, except this is asynchronous and does not actually push anything on to the view.

Now, with this function we can perform this call and then do a screen replace of the alert when the OK button is clicked.

App.onLaunch = function(options) {
    alert("Hello!", function() {
      var helloDocument = getDocumentContents("http://localhost:8000/hello.tvml", function(xhr) {
        navigationDocument.dismissModal();
        navigationDocument.pushDocument(xhr.responseXML);
      });
    });
}

Let’s also change our hello.tvml file to use the stackTemplate, since it’s more interesting to look at. A stackTemplate is a nice way to lay out a list of content with title’s and images. Here’s the example I’ll be using in my demo:

<document>
    <stackTemplate>
        <banner>
            <title>Which Artist Do You Prefer?</title>
        </banner>
        <collectionList>
            <shelf>
                <section>
                    <lockup>
                        <img src="http://localhost:8000/nina.png" width="256" height="256" />
                        <title>Nina Simone</title>
                    </lockup>
                    <lockup>
                        <img src="http://localhost:8000/coltrane.png" width="256" height="256" />
                        <title>John Coltrane</title>
                    </lockup>
                </section>
            </shelf>
        </collectionList>
    </stackTemplate>
</document>

So basically this is just the way a stackTemplate is laid out, the banner is the top banner, the collectionList is just something that contains many shelf objects, which is just something that contains section objects, which contains lockup objects. The lockup object is what actually contains our image and title. In my case I added some images to work with to my directory called nina.png and coltrane.png

tvOS stackTemplate Screenshot

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Developing tvOS Apps for Apple TV [Part 1]

tvOS - Apple TV SDK Released

Here’s what you’ll have at the end of part 2 of this tutorial if you follow along:

Looking for some help building your Apple TV tvOS App? I’m available for consulting and development, contact me.

Apple TV Developer Tools

Before we get started you’ll need the Xcode 7.1 beta, which you can download here:
Download Xcode 7.1 Beta
Note that this does require an Apple Developer account, and is currently pre-release, so some things may change!

One thing to note when installing is that there is a known issue if you rename the Xcode 7.1 app, apparently people do this. So just a forewarning… don’t do that or you’ll get a crashy tvOS Simulator.

Also note that while Yosemite is supported, the capabilities are limited. It is recommend that for tvOS development you use OS X 10.11 El Capitan or newer. The El Capitan beta can be downloaded here.

Let’s start with some simple definitions…

Becoming an Apple TV Developer – Vocabulary

TVMLKit

TVMLKit is Apple’s new framework designed for working with Javascript and XML to provide a rich user-interface on tvOS, while allowing your apps logic to be written in Swift or Objective-C.

TVML

TVML is short for “TV Markup Language” and is basically just some XML that describes how items are laid out in a client-server based tvOS app. When laying out an interface, we want to use some TVML templates that Apple provides to create our UI, and then we can script the interactions in TVJS.

TVJS

As far as I can tell, TVJS is just JavaScript like you might already be familiar with.

Hello World

Let’s start out by making a basic hello world. In terms of Apple TV, we could just log “Hello World” to the console and that would be a decent start, but let’s start digging in to some of the Apple TV’s TVMLKit elements and put up a template on-screen.

First, open Xcode 7.1 and create a new project. You’ll see a list of templates appear. On the left-hand side we want to select **CHANGE tvOS, and then select Single View Application* template.

This will create a number of files from the tvOS template which are going to be useful in setting up our UI, and gives us a simple entry point to start coding Swift as well.

Setting up the main TVJS file

So basically the “server” in client-server tvOS apps is the TVML and JavaScript files, and whatever associated data they need to operate. The JavaScript file will be what loads in the TVML, and adds the page to the view stack. Another way to think of this is that the JavaScript file acts as a router or controller for the TVML files which are basically the views.

Kicking things off

First, we want to make some modifications to the AppDelegate.swift file that launches the app. For one, we need our application to adhere to the TVApplicationControllerDelegate protocol. This is defined in the TVMLKit framework, so we’ll need to import that as well. So you’ll want to update your AppDelegate.swift to include those two items:

import TVMLKit
 
class AppDelegate: UIResponder,
                   UIApplicationDelegate,
                   TVApplicationControllerDelegate {
 
....

This interface has four functions that tvOS calls upon the implementing AppDelegate to notify our app of the lifecycle of the tvOS application. We don’t need to worry about these just yet, but we’ll dig in to these in later tutorials. For now, just add the protocol as shown in the code snippet above, and that’s enough to get us started.

Next, we need to add some code to actually launch our JS file. This is a beta, and actually requires we do this work ourselves, I’m sure in future Xcode version’s this will simply be a template.

In the application didFinishLaunchingWithOptions function we need to perform a few steps. These steps are unlikely to change for each individual app so you can simply copy this snippet here:

// We'll hold a reference to the app controller in an optional property
var appController: TVApplicationController?
 
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
 
  let appControllerContext = TVApplicationControllerContext()
 
  let jsFilePath = NSURL(string: "http://localhost:8000/main.js")
  let javascriptURL = jsFilePath!
 
  appControllerContext.javaScriptApplicationURL = javascriptURL
  if let options = launchOptions
  {
    for (kind, value) in options
    {
      if let kindStr = kind as? String
      {
        appControllerContext.launchOptions[kindStr] = value
      }
    }
  }
 
  self.appController = TVApplicationController(context: appControllerContext, window: self.window, delegate: self)
 
  return true
}

In short, what this code does is it gets a reference to an TVApplicationControllerContext, a class that simply provides some launch data to our AppDelegate class, and gives us an interface to make adjustments to the launch process. Then it passes the URL of the main.js file we’re going to execute, and sets the path for the app controller to be that path.

We need to now add our javascript file, so click File > New, and then under the iOS tab you can select an Other > Empty file. Name this file main.js.

Do the same thing for a new file called hello.tvml.

In your main.js file we’ll add some relatively simple JavaScript to load in the hello.tvml file:

function getDocument(url) {
  var templateXHR = new XMLHttpRequest();
  templateXHR.responseType = "document";
  templateXHR.addEventListener("load", function() {pushDoc(templateXHR.responseXML);}, false);
  templateXHR.open("GET", url, true);
  templateXHR.send();
  return templateXHR;
}
 
function pushDoc(document) {
  navigationDocument.pushDocument(document);
}
 
App.onLaunch = function(options) {
  var templateURL = 'http://localhost:8000/hello.tvml';
  getDocument(templateURL);
}
 
App.onExit = function() {
  console.log('App finished');
}

Now in the hello.tvml file:

<document>
  <alertTemplate>
      <title>Hello tvOS!</title>
  </alertTemplate>
</document>

This TVML file is the meat of the UI. Documents must use templates or you’ll get crashes at runtime with the code we’re using. It just contains a simple template and a single title element.

One issue I found with setting things up is that I was unable to locally refer to these files, and instead they have to be on a web server. So, what is easiest to do is navigate to the location of your tvml and js files we just created and type the following command in the command line:

Setting up the server to host the files

python -m SimpleHTTPServer 8000

This just uses Mac OS’s built-in python interpreter to start a web server on port 8000 serving up the local directory. If you copied my code shown above you should now be able to boot in to your tvOS simulator by pressing the play button in Xcode! There is one more issue you should be aware of, which is that this is an http unsecured request. In iOS 9 this is blocked by default by App Transport Security. In order to allow localhost to be used in this way, we need to add a key to the Info.plist file.

Allowing Arbitrary Loads

Select your Info.plist file and add a new record by pressing one of the (+) buttons. In the list find “App Transport Security Settings” and press return. This will create a new Dictionary row, expand this and press the (+) button on this row to add a child row. For this one find, “Allows Arbitrary Loads” and set it to true. With this in place we can run the app and preview using the simulator.

Adding Buttons

What you’re seeing in this example is actually a template from Apple called the alertTemplate. You can also embed a few basic controls, such as text and buttons within the template. Try adding a few buttons to select from:

<document>
    <alertTemplate>
        <title>Hello tvOS!</title>
        <button>
            <text>A Button</text>
        </button>
        <button>
            <text>A Second Button</text>
        </button>
    </alertTemplate>
</document>

Here we just are adding child button elements, each with it’s own child text element. This in turn displays the fullscreen alert and the two buttons on the tvOS simulator. The official Apple documentation has a list of each template, and control you can use if you want to hit the ground running. Otherwise stay tight, subscribe, and I’ll be bringing you a full tutorial of a fully developed app very soon.

Next Steps

Proceed to PART 2 » of this tutorial to learn how to add interactivity to the app.

If you want me to email you letting you know when new posts are up, be sure to subscribe to my newsletter.

These are still early days, so expect issues. If you get stuck don’t hesitate to contact me on twitter @jquave

GO TO PART 2 »

Looking for an Apple TV Developer for your tvOS App? I’m available for consulting and development, contact me for more info.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Objective-C Pointers and Swift 2: A Simple Guide

This post written on August 23, 2015 to be compatible with Xcode 7 Beta and Swift 2

Objective-C Pointers and Swift

Reading C pointers from Swift

Let’s say I have a C Int object as a Swift pointer.

For example this Objective-C method would return an int pointer, or (int *) in C terminology:


@interface PointerBridge : NSObject {
    int count;
}
- (int *) getCountPtr;
@end
 
@implementation PointerBridge
- (instancetype) init {
    self = [super init];
    if(self) {
        count = 23;
    }
    return self;
}
- (int *) getCountPtr {
    return &count;
}
@end

If you’re unfamiliar with Obj-C or C syntax, the above basically just declares a class called PointerBridge, and it has a single method called getCountPtr, which returns the memory address of an int whose value is 23. The Int is just a variable on the instance called count, which gets set to 23 in the constructor, init.

I put this in an Objective-C h-file and import it in to my bridging header in order to expose it to Swift. Then in Swift I create the PointerBridge class as a new instance called bridge, and get the result of the getCountPtr() method…


let bridge = PointerBridge()
let theInt = bridge.getCountPtr()
print(theInt)
print(theInt.memory)

Examine the type of theInt by holding the Option key and clicking the variable name in Xcode, and you’ll find it’s Swift type is a UnsafeMutablePointer<Int32>. This is a pointer to an Int, which is not the same thing as being an Int… It just points to it.

If we run this small program and allow this Swift to execute, we’ll see theInt printed to the console as a memory address, something like 0x00007f8bdb508ef8. Then, we’ll see the value 23 printed from the memory member. Accessing memory on a pointer generally returns the underlying object, in this case just the original 32-bit int (brought in to Swift as an Int32)

Now consider our Objective-C class also allows us to set the value of count.


@interface PointerBridge : NSObject {
    int count;
}
- (int *) getCountPtr;
- (void) setCount:(int)newCount;
@end
 
@implementation PointerBridge
- (instancetype) init {
    self = [super init];
    if(self) {
        count = 23;
    }
    return self;
}
- (int *) getCountPtr {
    return &count;
}
- (void) setCount:(int)newCount {
    count = newCount;
}
@end

Now, we could modify the value for count by calling setCount(). Since theInt is a pointer, updating the count value using setCount should also update theInt.memory. The memory address won’t change after all, just the value.

In other words, the following should log to the console the number 23, and then the number 1000.


let bridge = PointerBridge()
let theInt = bridge.getCountPtr()
print(theInt.memory) // 23
bridge.setCount(1000)
print(theInt.memory) // 1000

A shortcut you might want to take, to avoid writing .memory all the time, is to assign .memory to a variable:


let bridge = PointerBridge()
let theInt = bridge.getCountPtr()
let countVal = theInt.memory
print(countVal) // 23

As before, 23 is printed to the console. However, if I do the same thing we did before, and modify the underlying count value by calling setCount(), we see a problem crop up:


let bridge = PointerBridge()
let theInt = bridge.getCountPtr()
let countVal = theInt.memory
print(countVal) // 23
 
bridge.setCount(1000)
print(countVal) // 23

What’s happening here is that countVal is being assigned by value. At the time of assignment the value is 23, so countVal actually has it’s own memory address where it stores 23 permanently, thus losing it’s pointer nature. countVal is just a regular Int32 now.

Creating C pointers from Swift Objects

What if we wanted to do the inverse of what we did above? Instead of setting the value of count with an Int, what if we needed to pass in a pointer?

So in the Objective-C let’s say there was a method like this:


- (void) setCountPtr:(int *)newCountPtr {
    count = *newCountPtr;
}

This method is pretty contrived, and just ends up re-assigning the value of the newCountPtr, but in your Swift development you will face real-world scenarios of needing to pass in pointers. This one is contrived simply to demonstrate how to create the pointer type from Swift, and pass it in.

You might think you could simply pass in an Int value, with a reference operator like &. This is how you might do this same thing in C. Or for example in Objective-C you would write this:


int mcount = 500;
[self setCountPtr:&mcount];

Which would update the count value to be 500 successfully. However in Swift, you may see just from auto-complete that it wants something a little more complicated (and verbose). It’s looking for a newCountPtr of type UnsafeMutablePointer<Int32>.

I know this type is a mouthful, and it looks really complicated. However, it’s actually fairly simple, especially if you know pointers from Obj-C. In order to create an object with type UnsafeMutablePointer<Int32>, we just call the constructor and for it’s only argument we pass in the size of the pointer in units of the number of objects.


let bridge = PointerBridge()
let theInt = bridge.getCountPtr()
print(theInt.memory) // 23
 
let newIntPtr = UnsafeMutablePointer<Int32>.alloc(1)
newIntPtr.memory = 100
bridge.setCountPtr(newIntPtr)
 
print(theInt.memory) // 100

The only argument to the UnsafeMutablePointer<Int32> constructor is how many objects worth of space will be allocated, so we can just pass in 1 since we only need 1 Int32 object. Then, simply inverting what we did before with the memory property, we can assign a value to our newly created pointer. Finally, we can simply pass in the newIntPtr to the setCountrPtr method. Printing out the value of the original theInt pointer, we see the value has indeed been updated to 100.

Conclusion

The UnsafeMutablePointer<T> type, and it’s sibling UnsafePointer<T> are basically just abstractions of C pointers. If it helps to wrap your head around them, think of them sort of like Swift Optionals, in that they do not directly equate to a certain value, but instead act as an abstraction layer on top of a contained variable. The type is generic, and allows for other types to be used than just Int32. For example if you needed to work with a Float object you might need an UnsafeMutablePointer<Float>.

The important thing to remember is that you do not cast from an Int to an UnsafeMutablePointer<Int>, because a pointer is simply not the same as an Int value. So instead, be prepared to create a new object, calling it’s constructor UnsafeMutablePointer<Int>(count: Int).

We’ll follow-up this post with a deeper dive in to the details of function pointers, and how to take advantage of these features to work with legacy C and Objective-C APIs. Make sure to sign up for our newsletter so you don’t miss it!

Subscribe For Free Now »

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Swift 2 – What’s new

Monday Apple announced Swift 2, and just about everything announced is an extremely welcome change. This post is a summary of Chris Lattner’s discussion in the WWDC video “What’s new in Swift”. Now, let’s run through them…

Fundamentals

enums can now be printed to the console and show the actually value instead of just (enum value). Additionally, println is now just print. If you have ever used log debugging to figure out a problem involving enum values, rejoice!

I tested this and saw that not only is the enum value is printed, but so is the entire context of when and where the print() function is called.

enums can now support multiple types, so long to Box!

enum<T1, T2> {
  case First(T1)
  case Second(T2)
}

The do keyword:

do {
  //...
} while(someVar<5)

// Can now be represented as:
repeat {
  //...
}

Option Sets can now use a standard Set type in Swift 2.0

viewOptions = .Repeat | .CurveEaseIn
viewOptions = nil

// Can now be represented as a set:

viewOptions = [.Repeat, .CurveEaseIn]
viewOptions = []

We can also create our own set types

(Default implementations in protocols)

struct MyStyle : OptionSetType {
  let rawValue: Int
  static let Bold     = MyStyle(rawValue: 1)
  static let Italic   = MyStyle(rawValue: 2)
}

iStyle.style = []
iStyle.style = [.Bold, .Italic]

if iStyle.style.contains(.Bold) {
  //...
}

Function arguments now behave the same way, regardless of if they are global functions, or methods on a data structure.

So now, you provide arguments labels on functions by default:

func myFunc(name: String, age: Int) { ... }

myFunc("John", age: 35)

The # syntax is now gone, previously used to make the external argument name the same as the internal argument name.

In tests, public and internal are visible, via running a special run mode.

Pattern Matching
Added the guard statement which exits the scope in the else statement.

guard let name = json["name"] as? String else {
  return .Second("missing name")
}

// You can also combine this is to complex guards
guard let name = json["name"] as? String,
      let year = json["year"] as? Int else
    return .Second("bad input")
}
// name and year are now String and Int types, not optionals!
return .First(name, year)

Switch/case can now be used with inline if statements

switch bar() {
case .SomeCase(let value) where value != 42:
  doThing(value)

default: break
}

// Can now be represented as
if case .SomeCase(let value) = bar() where value != 42 {
  doSomething(value)
}

for in loops now support boolean filters and full pattern matching

for value in mySequence where value != "" {
  doThing(value)
}

for case .MyEnumCase(let value) in enumValues {
  doThing(value)
}

BONUS: Example of try-catch for JSON vs invalid JSON

let jsonString = "{\"name\":\"Fred\", \"age\":40}"
let badJsonString = "This really isn't valid JSON at all"

let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
let badJsonData = badJsonString.dataUsingEncoding(NSUTF8StringEncoding)!

do {
    // Try parsing some valid JSON
    let parsed = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments)
    print(parsed)
    
    // Try parsing some invalid JSON
    let otherParsed = try NSJSONSerialization.JSONObjectWithData(badJsonData, options: NSJSONReadingOptions.AllowFragments)
    print(otherParsed)
}
catch let error as NSError {
    // Catch fires here, with an NSErrro being thrown from the JSONObjectWithData method
    print("A JSON parsing error occurred, here are the details:\n \(error)")
}

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

WWDC 2015 Developer Highlights

Today Apple announced watchOS, delivering a new native SDK for developers at WWDC 2015, a new version of Mac OS X known as OS X El Capitan.

Mac OS X El Capitan

Shaking the mouse makes the cursor appear larger to make it easier to find.

Safari now includes “pinning” of tabs, which leaves permanent icons on the top of the tab view in the browser, and it also seems to precut so it loads instantly.

Spotlight is using natural language processing to greatly improve search functionality. For example, “mail i ignored from phil” to see emails not replied to.

Mail now supports multiple tabs for composing emails, and allows drag and drop between emails.

Mission control is now much simpler, supports left/right docking of windows similar to Windows 7.

Generally seems to have improved drag and drop support across the board.

Metal has now been ported to Mac OS, and has been implemented in the Unreal Engine.

iOS 9

Siri has greatly improved NLP.

Siri is now also proactive, for example if you listen to music while running, the lock screen can offer up your music. Then when you hop in to your car (which it can detect), it will switch to that audiobook you’ve been listening to.

Siri Suggestions can recommend news, nearby places, and people. iOS 9 also remembers when you use certain apps, and will recommend then on the lock screen in the same way Handoff does.

Siri is now context sensitive, “remind me about *this* later today” will create a reminder based on what is currently on-screen.

Search is greatly improved, integrating with YouTube, iTunes, and it provides an API for developers.

These features are collectively referred to by Apple as “intelligence”. It does not undermine your privacy. Everything is done on-device.

Notes is greatly improved, and added support for all types of interactive content.

Maps also greatly improved, transit and navigation integrate with Siri.

A new app called “News” has been added to iOS 9, a Flipboard-Like app directly from Apple. News supports recommendations based on your tastes, and provides multimedia support including video.

iPad

iPad now support a PIP-style multi-tasking, slipovers bringing in apps from the side and enter split view for true multi-taksing.

The Search API

iOS 9 SDK will provide an API for search, with support for deep links within apps.

iOS 9 SDK provides split view APIs, using just auto layout. Twitter was able to implement within a few minutes.

Swift 2

Swift will now be OPEN SOURCE later in 2015. With standard library support for Linux, Mac OS, and iOS.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Open Source Swift – A Look At The Top Swift Repositories

Github, the most popular open source repository for open source software, offers a feature that let’s us view repositories by language. In this post, I want to dissect some of the most popular Swift repositories as of June 5th, 2015. So, let’s kick it off with the most starred Swift repository, Alamofire.

Alamofire

Alamofire is an “Elegant HTTP Networking in Swift”, written by Matt Thompson, a well known Objective-C developer responsible for the AFNetworking library. The library takes the built-in iOS networking features and abstracts them away in to a simpler, and more Swift-y API.

Take for example the case of a simple GET request that returns JSON:

Alamofire.request(.GET, "http://httpbin.org/get")
         .responseString { (_, _, string, _) in
                  println(string)
         }

It’s the most popular library for Swift to date, so you should probably be using it, right?

Well, maybe… The library makes some common tasks simpler and less verbose, but if you don’t know the basics of networking in Swift (or Objective-C), it’s probably best to get a good understanding of the existing APIs first. After understanding what’s going on under the hood, you can make a more informed decision about whether or not you need the extra layer of abstraction. Alamofire is a big framework, and networking is a huge topic, so I don’t want to get too far in to the details on this library. But, suffice to say if you are working with complex networking requests with lots of back and forth with a web server, and/or working with a complicated authentication process, using Alamofire might reduce some of the repetitive coding tasks. If you are new to iOS development, I would recommend just stick to the APIs provided by Apple for now.

SwiftyJSON

SwiftyJSON is “The better way to deal with JSON data in Swift” according to it’s Github entry. This framework is one of the first I saw when Swift was first released, that combined with the fact that JSON parsing is such a common problem is how it became a top repository, helping to deal with the messiness of Apple’s built-in JSON parser. In particular, the static typing of Swift and optional syntax led to a lot of verbose JSON parsing code, guessing and checking each step of the way for each key and checking every cast. The truth is though, using this library is VERY similar to just using optional chaining and Swift’s normal casting syntax. There is not much benefit here, and from what I’ve seen in production, SwiftyJSON has some performance problems, as a result I’m not sure I would recommend using it right now, except in prototype apps, or during the learning phase.

Take a look at the example they give as the standard approach to parsing JSON, which they describe as “not good”:

let JSONObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil)

if let statusesArray = JSONObject as? [AnyObject],
   let status = statusesArray[0] as? [String: AnyObject],
   let user = status["user"] as? [String: AnyObject],
   let username = user["name"] as? String {
    // Finally we got the username
}

They then present their alternative version of the syntax:

let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string{
  //Now you got your value
}

There’s a few issues here, first of which is that the simplifications they are showing are partially just taking advantage of language features that would actually work with the regular parser. Second, it seems like their example actually would not work.

Based on the example code shown above, the example JSON they are parsing looks something like this:

{
    "statuses": [
        {
            "user": {
                "name": "Bob"
            }
        }
    ]
}

One issue with this sample right off the bat is that they are casting the initial value of the JSON to an array, which would suggest that the root element is an array, which is invalid JSON. The type of the root object in valid JSON is always going to be a key/value. Or equivalently in Swift, a Dictionary of type [String:AnyObject]. Additionally, it’s good practice to actually check if the JSON parsing succeeded or not.

Once we start going through and fixing all the issues with the sample code, assuming we want to explicitly cast everything as they have shown, we end up with something like this:

if let JSONObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject],
    statusesArray = JSONObject["statuses"] as? [[String:AnyObject]] {
        let status = statusesArray[0] as [String: AnyObject]
        if let user = status["user"] as? [String: AnyObject],
            let username = user["name"] as? String {
                println("username: \(username)")
        }
}
else {
    println("Failed to parse JSON, handle this problem")
}

Now, this is in fact pretty verbose, and could be reduced quite a bit, but let’s stop a think about what we’re doing here. In this example, we are trying to download a list of statuses which are owned by users, and they have names. In an actual Swift application, I would expect there to be a model representing these objects. Maybe something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

Assume we are using SwiftyJSON for a moment, how would we add these records to the model of our app? Maybe with a bit of code like this…

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}

This works relatively well, assuming we are just creating objects from a JSON feed rather than synchronizing them. But what if there is a server error and the JSON comes back invalid? For example if there is a server error which changes the JSON to present an “error” key, and it no longer includes “statuses”, this loop simply would not be executed. Failing silently is better than crashing, but it would be nice to check for issues and try again, or adjust something in the app.

Since we need to check for the presence of statuses, and this for loop doesn’t actually do that, we need to check the count of statuses first, which means we need to cast it to an array, and *then* check the count…

if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}

And that's that! Right?
Well, no...

If the key isn't defined, this count property evaluates to 0, which could just mean there is no new statuses to see. The count really should not be zero, it should be null.. but SwiftyJSON is telling us it's 0. This seems like the kind of thing I really *don't* want a JSON parser to be doing. They really seem to not like the optional syntax in Swift, and instead reinvented it with these type properties. Why not just stick with convention?
Our final code might look something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}
if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}
if let err = parsedJson["error"].string {
    println(err)
}

Our code is starting to grow, and this doesn't cover a ton of things we would need in a real-world application, such as updating the model, including more properties, checking for equality, enforcing uniqueness, cascading relationship changes, and a host of other things. Core Data can handle much of this, and it's common practice to implement models as Core Data models, but that still creates a situation where we have to custom implement all kinds of methods for converting the entire model object (such as Status) *back* in to JSON to update the server.

In the Objective-C world there is Mantle, a great library for handling such things. Before that there was RestKit. RestKit however made some ...interesting... design decisions a few years ago in a big update, and haven't ever really recovered since then. Unfortunately I haven't found a good solution for Swift just yet, and trying to work with Mantle proves to be problematic in it's current form, unless you implement all your models in Obj-C, something I'm not sure we all want to do at this stage.

I know this isn't all problems with SwiftyJSON, but they ironically break a lot of Swift conventions in dealing with optional values. SwiftyJSON is really a terrible name, they are very much not Swifty at all. However, the syntax is a little easier on the eyes. Personally, I don't use the library in my projects.

Spring

Spring is "A library to simplify iOS animations in Swift." How does it do this? Let's take a look.

Trying out some sample code I threw together this quick demo UIViewController that adds a blue square to the screen and animates it in, give it a try yourself, it's pretty nifty:

import UIKit
import Spring

class ViewController: UIViewController {
    var square = SpringView(frame: CGRectMake(0, 0, 200, 200))
    override func viewDidLoad() {
        super.viewDidLoad()
        
        square.center = self.view.center
        square.backgroundColor = UIColor.blueColor()
        square.animation = "squeezeDown"
        square.animate()

        self.view.addSubview(square)
    }
}

The SpringView seems to basically just be a UIView subclass with the animations added in. I don't know if I really like the idea of having to use their UIView, but I suppose most of the time I just use the basic UIView, and even if I didn't, I could just subclass SpringView instead.

Spring sports quite a few animation types, set as a string. The square.animation = "squeezeDown" here is what's determining the animation to play. The library goes beyond this, and in fact allows simple animations to be created in storyboards. So in theory you could put Spring in your Xcode project, and then pass it off to a designer to set up some nifty animations using this library. Very interesting idea, I would like to hear from someone who has tried to do exactly this.

Quick

Quick is "The Swift (and Objective-C) testing framework."

Really? It's THE testing framework? Let's take a look at how Quick works as opposed to XCTest, or expecta.

In XCTest, you might define an assertion that you're testing against like this:

class JSONSwiftTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testContrivedExample() {
        let name = "jameson"
        XCTAssertEqual(name, "jameson", "Name should be \"jameson\"")
    }
}

This is okay, it makes the test basically confirm that name is equal to "jameson". It's simple enough, but there is a common trend/desire among developers to instead express test cases in terms of desired behavior, rather than specifically implementing what the desired behavior causes. Those may sound like the same thing, but take a look at how Quick (due to it's usage of the library Nimble) expresses the same thing like this:

import Quick
import Nimble

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
    }
}

More than anything else, this framework encourages behavioral tests, which is why this example includes more information about our expectations.

Quick also eases some of the pain of asynchronous testing. In XCTest I personally tend to use XCTestAsync, although Xcode 6 does introduce a way to do this using XCTestExpectation. The basic way that works is you can create an expectation object, and then fulfill it when the async operation is complete. It's not a bad approach.

import Quick
import Nimble

@objc class AsyncExample {
    var longTaskIsDone = false
    var timer: NSTimer?
    func startLongTask() {
        timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "taskIsDone", userInfo: nil, repeats: false)
    }
    func taskIsDone() {
        println("task done")
        longTaskIsDone = true
    }
}

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
        
        describe("Async Example") {
            describe("its long task") {
                it("should finish in 5 seconds") {
                    let asyncExample = AsyncExample()
                    asyncExample.startLongTask()
                    expect(asyncExample.longTaskIsDone).toEventually(beTruthy(), timeout: 3, pollInterval: 0.4)
                }
            }
        }
        
    }
}

In this example we just create an NSTimer that fires in 2 seconds, as a simulated async example. Then in the Async Example test, we can use the .toEventually() method to wait around and keep checking in to the asyncExample.longTaskIsDone property. This is slightly cleaner in that using expectations, because with this method we don't need to change our code to make sure the test is notified of this variable changing. Having an ongoing timer keep checking is great (just be careful not to have it calling methods with side effects!)

Overall Quick seems pretty interesting, the approach is sure to appeal to those in professional environments, or working with an Agile team where specs change fast.

That's it for this time, if you would like to see any of these libraries covered in greater detail be sure to let me know. You can find me on Twitter.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Swift 1.2 and Xcode 6 Beta 2 – The best update yet

The big news in the Swift community is the release of Swift 1.2, featuring some awesome features. Apple wrote about that a bit here, this was before they released Xcode 6.3 Beta 2, which came out today. But it contains most of the major language changes.

Xcode 6.3 Beta 2

First of all, Xcode itself has changed to allow for more easy to use playgrounds. In particular Apple has added rich text comments, in addition to showing results inline rather than in a separate timeline view. Swift performance was also further improve, and an additional method called zip was introduced for merging Swift sequences together.

zip()

Zip is a method that comes straight out of Haskell which accepts multiple sequences of data, and returns a single tuple “zipping” the two data sets together. For example

let a = [1,2,3]
let b = ["a","b","c"]
let zipped = zip(a, b)

Here the value of zipped would become two sequences in a tuple with types [Int] and [String]. Casting this to an Array makes the significance of this a little more clear:

println(Array(zipped))

[(1, a), (2, b), (3, c)].
As you can see the two sequences are simply “zipped” together. This does beg the question though, what if the sequences are of differing lengths?
For example…

let a = [1,2,3]
let b = ["a","b"]
let zipped = zip(a,b)

In this case, the zipping process will use the shortest sequence’s length as the number of elements to zip, and simply discard the trailing elements on the longer sequence. Giving the output, [(1, a), (2, b)]

This is particularly useful when working with what are effectively infinite sequences. You can limit the list by zipping with a finite sequence:

    let squares = Array(map(1..<10) { $0 * $0 })
    let names = ["one", "two", "three"]
    
    let squareList = zip(names, squares)
    
    println(Array(squareList))

Results in:
[(one, 1), (two, 4), (three, 9)]

So, even though the squares sequence can go on forever, it's made in to a finite list due to the fact that names has only 3 elements.

Goodbye pyramid of doom!

The optional binding sometimes leads to messy code like this:

if let first = user.first {
  if let last = user.last {
    return "\(first) \(last)"
  }
}

But with 1.2, these series of if let statements can be collapsed down to just a comma separated list of optional values, and only a single set of curly braces. The above code will behave exactly the same as this:

if let first = user.first, last = user.last {
  return "\(first) \(last)"
}

Sometimes these chains upon chains of optional binding statements can get out of hand, so this is a very welcome feature. As an additional bonus in Xcode 6.3 Beta 2, we can now also add a single optional binding let clause. For example:

if age > 17 && profile.public,
  let first = user.first,
  last = user.last {
    return "\(first) \(last)"
}

This code will not only perform the optional binding in a more concise way with the variables first and last, but it will only do so if the user is of age and has a public profile available, which are assumed to be boolean values in this example. Contrast that with how we wrote this in older versions:

if (age > 17 && profile.public) {
  if let first = user.first {
    if let last = user.last {
      return "\(first) \(last)"
    }
  }
}

The as! keyword was added

When casting from one type to the other, it's possible that the cast could fail. Previously this was handled with the case of an optional using the as? operator. Consider the scenario below

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as String
bio(nameStr, location)

Here we are calling a function that requires a String, but we have name typed as an AnyObject object. Before Swift 1.2 this code would be accepted, but this could actually crash your application if the cast fails. In this case it would never fail, so we can safely do this cast, but the syntax shown above does not clearly demonstrate that this cast is actually dangerous. If name gets changed to something that is not castable to a String later, this code would cause the app to crash. In order to more clearly communicate this, the as operator must now become as! if the cast could possibly fail. So the above would now become this:

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as! String
bio(nameStr, location)

This helps drive home an important message: If you are using an exclamation mark (!), then you may be setting up a situation where the app could crash due to a failed cast, or null value. As a general rule, you should just never use forced casts unless you absolutely have to (or if you're writing code that won't go in to production)

Keep in mind the as? keyword is unchanged, and in general you should prefer using it in addition to an optional binding for this type of scenario, as this is much safer, e.g.

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
if let nameStr = name as? String {
  bio(nameStr, location)
}

Xcode and Compiler Improvements
This is probably the biggest one for me. The compiler is faster due to incremental builds, and Xcode doesn't crash all the time due to some stability improvements. This alone makes the beta work the download and I highly recommend getting a copy on iOS Dev Center.

Want to learn more about Swift 1.2? Try out some of my free tutorials. My Core Data tutorial was updated recently for 1.2, which I would recommend to anyone interested in working on real iOS Apps.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS

Should I learn Objective-C or Swift first?

“Should I learn Objective-C or Swift first?”

I get asked this question a lot. Sometime’s people will also ask about learning C or C++ first. So, I want to take a moment and give you the low-down on how I feel as a professional iOS & Mac developer, six months after Swift’s introduction. If this is your first time here, here’s a little background on me:

About me…

I’ve been developing software for as long as I can remember, at least 20 years now. I never was really the Mac guy, but I liked Linux and was always looking at new technologies. So, when the iPhone came out in 2008, I got myself a Mac and entered that ecosystem. Around that time I learned Objective-C, and that became my primary development language. It has been since then, and I’ve seen the language and Mac/iOS APIs twist and turn this way and that for the past 6+ years. In June I picked up Swift for the first time like everyone else, and although I still won’t call myself an expert, I will say I’ve done extensive study on the language. I’ve developed (and released) 3 apps using Swift since the announcement. Learning Swift is something I think is really important to iOS developers now, in fact it’s critical. To help people out I decided to write my Swift Book. This also serves as a way to help me learn the language, but I have already seen what a valuable resource it is for others; it’s exciting to be a part of… Additionally I’ve worked on an SDK that uses Swift, which will be used as part of a major platform worldwide in 2015. It’s very exciting to ship something like this that so many other developers will be using.

So, that’s my Swift-related experience in a nutshell. Now, here’s how I want to answer your question…

So… Swift or Objective-C?

Part of me wants to say, “Yes, go learn C first and then Objective-C. That’s what I did, so that’s what you should do.”

But here’s the thing: Just because that’s the path I took, doesn’t mean it’s the best path today. When I was first learning C, people told me I needed to learn Assembly to really get what was going on. They told me that without an underlying understanding of Assembly, I was going to be forever writing code and not understanding it. I ended up ignoring this advice and was very happy and successful as a developer without Assembly knowledge. In my college years, I finally picked up Assembly as part of my Electrical Engineering degree program. It helped enlighten some things, but for the most part I don’t feel knowing Assembly had much of an effect on my day-to-day programming. It had no effect on how I separate objects, how I decide what gets encapsulated, where to inherit, or where to compose. Most importantly, it didn’t help me to build better software. It was basically just academic, and as interesting as it was and is, the only place it’s even remotely relevant day-to-day is in debugging or reverse engineering; and only in limited capacities.

There’s certainly some sort of fear in me, like if we don’t all learn Assembly it will become a lost art. But, I don’t think that’s a realistic concern, honestly. The more I think about the idea of Assembly becoming a lost art the more I realize it will never happen. A single preserved book on the topic can get anyone where they need to be to be productive in Assembly, you just probably don’t want to.

Computer Science is an industry where we need to let go of the past, and we need to do it as quickly as we can. This industry is not going to wait for you to learn all the languages leading up to the latest and greatest. The marketplace certainly won’t reward that. What it will reward though, is knowing how to write code to make working software. That’s sort of the general thesis of this site, and it’s why I produce it. I don’t want to teach you to write code; I want to teach you to make software.

So here’s my answer to your question:

Swift

You should learn Swift first. You should learn it first because it’s the future of development on Apple platforms, and frankly it’s just easier to understand than Obj-C or C. What you may find as you learn it is that the Cocoa framework is getting a little stale. It’s starting to look very much like an Objective-C API in a Swift world. But that’s probably going to change. This wouldn’t be the first time Apple made a major change to their underlying APIs. Back in the days before Cocoa developers used Carbon, a C-based API that had some interoperability with Objective-C.

Apple is well-known for making swift (get it?) changes to their development stack. The move from Mac OS 9 to Mac OS X is a great example of their commitment to innovation. As a developer on Apple platforms, it’s important to understand this fact. Apple is about building the future of technology products, and they are not afraid to forego backwards-compatibility in order to achieve that. If you are still writing Objective-C day-to-day, you’re writing legacy code at this point. If you are writing Swift, then welcome to our world, you are the future.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Subscribe via RSS