A C# developer learns Swift Part 1: Core Data
I’ve always been a PC guy until a few years ago when I bought an IPad 2 for my wife. Since then, most of my personal electronic devices have been converted to Apple. As a user, they’re really great. So naturally, I though I’d give Apple development a shot as well. I got about 2 chapters into a book on Objective C, before I gave up. The majority of my professional career has been in Java and C#, and Object C just felt really dated in comparison. The dev tools also felt lacking when measured up to what you can do with Visual Studio these days. Plus, I have a thing about languages without a true boolean type.
It’s weird, I hadn’t visited slashdot in about a year, and the one day I happen to check out the headlines was the same day that Apple announced Swift. I was immediately interested, and dived into the language specification. It was almost like a real modern programing language. Garbage collection and everything. There was some weirdness. Lack of a try/catch construct and no reflection, but still much better than the alternative.
In order to teach myself the language I came up with a simple app to implement which would cover a good breath of the framework features provided. Here at SEP we do a lot of informal design on paper and whiteboards. After which, the smartphone usually comes out to snap a pic to refer to later. My learning app is a tool for capturing these types of informal design artifacts, organizing them by projects and allowing the user to capture any relevant notes on the design. I’m calling it Scribble for now.
Part 1: Core Data
The first real barrier to learning swift is that it has no native API. Instead it bridges into the existing Objective C libraries. Most resources on the net right now are still geared towards using these libraries with Objective C. Not to mention the unique quirks from the Swift to Objective C bridge that people don’t have a good handle on yet.
Core Data is the persistence framework that is provided for IOS development. It’s a typical ORM that abstracts a SQLite database(it can map to other data stores in the OSX environment).
First things first, when you create your Swift app make sure to set it up for swift and include Core Data.
Doing this will auto-generate an AppDelegate.swift file(kind of like your App.xaml in C# land) with the right hooks for Core Data.
Defining your persistent objects in Core Data is done in two parts. The first part is with a visual schema designer that defines what gets stored, and the second is through an object that represents the data in the code. The schema is located in a *.xcdatamodelid file that should have been created in your initial project. Within this view you can define your persistent entities and their properties.
In this example I’ve defined a “Project” entity with a single String property called “name”.
Next you’ll need to define a swift object to store the data in when it is retrieved for the DB.
A few things of note here. First, is that because Core Data is an Objective C framework, you need to let the compiler know that this swift class is visible to Objective C code. You do this through the “@objc” attribute; passing in the name of the object type. Your Core Data object will also have to extend the Objective C “NSManagedObject” type. Finally, the properties need to be marked with “@NSManaged” to indicate that these are persisted fields.
In order to work with your new schema and data types you’re going to need to get a handle to your application’s managed object context. This is located on your AppDelegate, and you can call it up like so:
With a reference to the context you can begin creating and retrieving data. Storing a new entity in the database is pretty simple:
You have to get the schema entity and use it to generate a new Project object. Once you set it’s properties you need to save the context to persist the new project. In this case, I’m passing in nil to the context.save() function. Normally you would pass an NSError object, but I’ll leave proper error handling for later.
Retrieving the data is done through a fetch request.
The returnsObjectsAsFaults flag seems to be a bit of necessary boiler plate for getting Core Data to play nice with swift. Sometimes it works with it, sometimes it doesn’t. It’s something I’m still investigating.
The real tricky part about fetching data is that all arrays returned from Objective C are NSArrays of AnyObject. This requires some explicit down-casting before you can work with the results. The NSArray to Swift array bridging also looks like a bit of a work in progress at this stage. The example above works just fine for looking at the properties on the results, but will error off if you try to put the project loop variable into an Array
You can filter your searches by adding a predicate to your fetch request.
In this case I’m looking for all projects with the name “Bob”.
My Scribble app will need to define a list of scribbles for each Project, and Core Data allows you to map entities to each other. So I created a new Scribble type that extends NSManagedObject and gave it a project:Project property. Then I added a scribbles:Array
Setting the destination and inverse on the relationship is pretty straight forward, but they hid the relationship type very well. You need to open the inspector and set the type. The buttons are highlighted in red in the image.
There you go, a basic intro to using Core Data with Swift. A thing to note, you’d better get used to seeing the “unrecognized selector sent to instance” error. Selectors are a feature of Objective C that seem to be leveraged very heavily in the bridge between the two languages. Whenever you get a error back from the UIKit or Core Data libraries 90% of the time it will be an error of that type, and 100% of the time it will be completely unhelpful. You’re going to have to basically poke at things until you get it right.