Response: The Laws of Core Data
Recently, I saw a post from Dave DeLong and knowing his history with the framework I read it with extreme curiosity.
Unfortunately, that read led to this post as I disagree strongly with a number of the laws he has laid down.
Since I know people are going to be asking me about this post (I am still getting asked about Simmons’ post from a VERY long time ago), better to get my thoughts out now.
1. Do not use Core Data as if it were a database
No disagreement; Core Data is your object model and it can persist to a database but that is not its biggest strength.
2. Do not use Core Data as if it were a SQLite wrapper
This is re-iterating #1. Core Data is your object model, not a thin wrapper around a database.
3. Your NSManagedObjectContext
is your “stack”
Here is where we start to disagree. The NSManagedObjectContext
is not your stack. It is a scratchpad. It is where you stage changes to the data objects and decide to persist them or not.
I have advocated putting an object around it for convenience and Apple added the NSPersistentContainer
which is designed to be subclassed. That wrapper is a great place to handle migrations, importing, exporting, convenience methods for accessing data; the list goes on.
All of the internal workings of your Core Data stack, your persistence and data model absolutely should be stored in the persistent container and that container should be injected through your controllers in your application.
4. Never ever ever ever ever use an NSManagedObject
outside its context’s queue
No disagreement. Core Data is designed to work in a threaded environment but most of the objects are NOT designed to work on multiple threads/queues. As with ANY object, assume it is thread locked unless you can demonstrably confirm that it is safe to use across threads.
5. Do not use NSManagedObject
as if it were an NSObject
An NSManagedObject
is an NSObject
that has additional functionality added. It should absolutely be treated as if it is an NSObject
because it is an NSObject
. NSManagedObject
instances are your data objects and should be treated as such. Creating Plain Old Objects on top of NSManagedObject
instances is asking for pain and data corruption.
6. You usually don’t need parent-child contexts
If you are not accessing the network, exporting data, importing data or interacting with the outside world in any way, shape or form then this is correct.
If your app talks to anything else then you will want to use parent-child contexts.
The parent context should be on the user interface thread (the main thread) and when you need to do asynchronous work with your data objects (importing or exporting) then you want to do that on another thread and that work should be done in a child context.
A child context simplifies the transfer of notifications of data changes and greatly simplifies using Core Data in a multi-threaded environment.
7. Keep your main queue context read-only
The main queue is also known as the user interface queue. The context that is associated with that queue should be for the user. That context reads and writes data when the user is interacting with the application.
Should it be read-only? Absolutely not.
Should it be user-only? Absolutely.
Any non-user work (importing and exporting) should be done on a child context on a background thread (see response to #6 above).
8. Use an abstraction layer
Please do not do this. You are going to make the next developer curse your name in a very unpleasant manner.
Use Core Data in your user interface. Do not create dummy data objects on top of Core Data. That leads to a maintenance nightmare.
Your user interface can use Core Data without really knowing that it is using Core Data. Your user interface treats the NSManagedObject
instances as if they were data objects because they are data objects.
Your user interface does not need to know any more about Core Data than it does for any other model structure. Your user interface should talk to your persistent container subclass and ask for the data it needs. The response to that request might be instances of NSManagedObject
or might be an NSFetchedResultsController
which then serves up the data objects in a consistent and reliable way.
9. Use Core Data as a local cache
I agree with the wording of this rule but I suspect the meaning is different. Core Data, like any local persistence, is a local cache of what is on the server. This is not specific to Core Data because that is what any local persistence does when you have data on a server.
Core Data is more than just a local cache.
Core Data is not complicated
Core Data is as complicated as you make it. Most of the time you do not need or want the advanced features of Core Data and can just grab an instance of NSPersistentContainer
and be happy.
When you need to deal with more complicated or interesting situations there is a fair chance that Core Data has an advanced feature to handle that situation. For the 80%, you can ignore those advanced features and relax in the comfort knowing they are there for if/when you need them.
The harder your code is to write the harder it is going to be to maintain and debug.
Don’t make it harder on yourself. Keep it simple.
Developer Review: 2017 MacBook 12
After much consideration and review, I recently purchased a 2017 MacBook.
No, not a MacBook Pro 13 or 15. I purchased the 12 inch MacBook. The small laptop that people say over and over again cannot be used for development.
This is a living review of that MacBook as used by a macOS/iOS developer.
(more…)
A Modern Network Operation
When Apple introduced the NSURLSession
API, the landscape of network operations changed. In some ways, the new API made things worse as the block API that was added tempts developers to become very sloppy with network calls. The block API makes it trivial to add network calls anywhere in an application. Very little thought or structure is required. From this (and some third party libraries who followed the same pattern) we have seen an explosion of increasingly poor network handling in applications.
For my own purposes I have resisted this slippery slope as often as possible. However I still preferred the way NSURLConnection
worked and how it integrated nicely with NSOperation
subclasses. My attempts at using the NSURLSession
were cumbersome and didn’t feel “right”.
Fortunately, I have recently worked on a design that I have been quite pleased with. In this design I am happily using NSOperation
subclasses again and I am using the NSURLSession
API.
(more…)
Swift Type Constrained Extensions: Express Yourself
I admit it. I was pretty down when Swift was announced. I appreciated the finer points of the reasons for it, however, they weren’t convincing–at least not to me–not at first. I denied that it was actually “expressive” as the overall community was referring to it, however, that was before version 2. It’s at the point when the lights went on for me. I am now a convert and this post explains why–at least one of the reasons. The only question I ask now is while you can do some really cool expressive things, should you? You’ll see what I mean if you read on.
(more…)
Massive View Controllers
While at Empirical Development and then MartianCraft I had been distanced from all of the inventive solutions that other development teams have been coming up with for the past few years. I was living in a bubble of our development teams.
Now that I am working independently again, I am being exposed to a large number of interesting code bases.
It came as quite a surprise to me that view controllers are considered bad by many developers and that they have been coming up with some rather intersting solutions to make them more “manageable”.
To me, this is an indication that many developers have lost the perspective on what should and what should not be in a view controller. For some reason there is a misconception going around that everything belongs in the view controller.
Madness!
Lets break it down.
(more…)
The Next Chapter
As of August 1, 2015 I am no longer part of MartianCraft.
It is time to move on to the next chapter.
What is Next?
Long term I have some ideas that will take a bit of time to put into place. In the short time I am eager to help as many teams as possible through short term contracting, consulting and workshops. I really do enjoy helping teams get the most out of their persistence and networking layers.
Therefore…
Effective immediately, I am available for short term and possibly long term contract work.
While I can assist with any form of iOS or OS X development, my area of expertise is in networking and persistence; specifically Core Data.
If you are not familiar with my experience, here are a few highlights:
- Wrote “The Book” on Core Data.
- Taught at universities around the United States
- Spoken at nearly every Apple related tech conference around the world
- Provided workshops on persistence, Core Data and Networking at many conferences and large corporations in and around the United States.
- Developed some of the most complex applications ever conceived for the iOS platform
What are the options?
I am looking for short term projects unless it is truly amazing, cutting edge, and never done before. I am looking to help your team provide a better experience for your users.
We can accomplish this either through a monthly, weekly, daily contract or through a workshop. The details of which we can discuss in detail. I am available to travel and can work on site for short periods of time.
Are you struggling with your persistence or networking layer?
Are you having performance issues that you are unable to isolate?
Would you like a fresh set of eyes on your project to get an idea of where things are?
Contact me; we can discuss the options.
Core Data and Aggregate Fetches In Swift
You can find other articles on the interwebs about NSExpression
and NSExpressionDescription
, however, I wasn’t really satisfied with the explanations I’ve seen. I decided to write a post myself after I recently had to become much more intimate with the way Core Data aggregate fetches work. I hope this will make clear what has to be done in order to harness this powerful feature of Core Data.
You’ve heard it said before and sometimes in a scolding tone, “CORE DATA IS NOT A DATABASE. IT’S AN OBJECT GRAPH!”. What normally follows is a discussion about what that means, if you’re lucky. Otherwise, you’re just on your own to go figure it out. In my mind, though, it’s not necessarily wrong to think of it as a database as they have enough things in common to make it a reasonable thing to do and at the end of the day Core Data is backed by a SQLite database. I think that if it helps you understand what is going on behind the scenes better, then go for it. You do have to remember some key differences that can bite you like the need to fetch before updating or deleting, for example. Though with recent additions–last year with iOS 8’s NSBatchUpdateRequest (link to iOS 8 API diff since it’s not currently documented) which allows you to perform a batch update similar to a SQL update query or this year with iOS 9’s NSBatchDeleteRequest
(See WWDC 2015 session 220 for more info) which allows for batch deletes based on whatever predicate you give it, the lines seem to be blurring more and more. (more…)
Xcode Continuous Integration: “Server encountered an error with Apple Developer”
If you get this message when you are adding your server to a team to implement continuous integration using Xcode bots and OS X server:
Server encountered an error with Apple Developer.
Please try again later. If the problem persists, contact Apple Developer Technical Support for help.
It could be a red herring. There’s a support note here: https://support.apple.com/en-us/HT203853 that states the issue has to do with making sure you login as an Agent or Admin. That’s probably a valid scenario, but it may not be as in my case. I got this error message simply because an updated program license agreement needed to be accepted on the web portal. Once that was done, I was able to add the server to the team and could continue on.
(Yes, I know it’s April first, but this is not a joke)
MCE Conf 2015
Late last year I was contacted by the organizers of MCE Conf and was asked to speak. Since it fit within my schedule (which can be its own challenge these days) I accepted without thinking too much about it.
Shortly after my acceptance I had heard that there was some controversy surrounding the conference about a comment made by one of the organizers who had attended another conference. After reading up on the controversy I figured; “oh well, how bad can it be?”
The short answer? It was amazing. I absolutely loved every minute of the conference.
(more…)
We’ll Miss You Jordan
Until today we had no category for a post like this. It now exists…
We offer our deepest condolences, thoughts, and prayers for all those affected by the tragic loss of such a great friend to this community, Jordan Breeding. He lost his fight with cancer this morning and we grieve deeply along with the rest of you. Jordan will be sorely missed.
Sincerely and with heavy hearts,
- Marcus, Matt, and the rest of the CIMGF family.
Beginning iOS Development With Swift
Many years ago now, I wrote a tutorial for the beginner to learn how to use outlets and actions as this is often one of the least familiar aspects for new developers who are wanting to learn iOS. It’s simple once you’ve seen it, but until then, there’s a gap. This time around I’m presenting an application that is similar to the one I did back then, however, it’s up to date with Xcode 6 and Swift. If you are new to iOS development, this should help get you going.
Beginning iOS Application Development with Swift from Skye Road Systems on Vimeo.
Swift and valueForKeyPath: You Can’t Keep A Good API Down!
tl;dr; Download the Value For Key Path Playground
I was incredibly disappointed in Swift when I started to look into how key value coding might be preserved in the transition from Objective-C. Of course, Apple would preserve that, right? And I don’t mean by resorting to using Foundation classes–you know all type-casty and everything (yeah, type-casty). Are we progressing forward or looking to the past, after all? I shouldn’t have to rely on NSArray like this:
var values = (items as NSArray).valueForKeyPath("value")
Right? Who wants to do that? What’s the proper Swift way?
Well, my early assumption from what I was seeing in Swift was that valueForKeyPath: was gone and no longer did we have a convenient way to grab only the fields we needed from a collection of objects. It appeared that it couldn’t be done–at least not in any idiomatic elegant way. Then I downloaded some sample code from the Apple developer site and noticed they were doing what I needed, but using map to do it. The answer was map. Here’s an example:
var lastNames = items.map({$0["last"]! as String})
Now the lastNames variable contains a list of strings with just the last name property of my items array. Given an array of dictionaries like this, you can see how that is providing pretty much what we used to get from valueForKeyPath:
var items = [
["first" : "Billy", "last" : "Bogart", "address" : ["street" : "111 Main Street"]],
["first" : "Gary", "last" : "Gollum", "address" : ["street" : "2277 AB Street"]],
["first" : "David", "last" : "Dangerly", "address" : ["street" : "22311 Place Ave."]],
["first" : "Johnny", "last" : "Jones", "address" : ["street" : "10 Orange Rd."]]
]
lastNames now contains:
["Bogart", "Gollum", "Dangerly", "Jones"]
Notice we also have an address property that points to a dictionary. If want to get the street property inside of address, we can drill down the same way:
var streetAddresses = items.map({ $0["address"]!["street"] as String})
Now, you can see we had to force-unwrap the address property in order to access the street property. This works perfectly and is a fine replacement for valueForKeyPath: of old. When the call succeeds we now have all of the street addresses in the streetAddresses array:
["111 Main Street", "2277 AB Street", "22311 Place Ave.", "10 Orange Rd."]
Take a look at the Value For Key Path Playground if you want to see it in action.
What About Safety?
In Objective-C, if you message nil, it’s a no-op. In Swift, however, if we unwrap an optional that is nil, we will crash. So, on this line:
var streetAddresses = items.map({ $0["address"]!["street"] as String})
when we unwrap using the bang ! operator, if that value doesn’t exist, we’re in trouble. Say our data was changed to this:
var items = [
["first" : "Billy", "last" : "Bogart", "addr" : ["street" : "111 Main Street"]],
["first" : "Gary", "last" : "Gollum", "addr" : ["street" : "2277 AB Street"]],
["first" : "David", "last" : "Dangerly", "addr" : ["street" : "22311 Place Ave."]],
["first" : "Johnny", "last" : "Jones", "addr" : ["street" : "10 Orange Rd."]]
]
Notice the address field has been changed to addr. This causes a crash.
Meanwhile, with the old Foundation way, we do this:
var oldStreetAddresses = (items as NSArray).valueForKeyPath("address.street") as NSArray
but look what the output is. NSNull!
[NSNull, NSNull, NSNull, NSNull]
No crash. So which is better?
Well, if your data can be unpredictable, which really shouldn’t happen, then the Foundation outcome is “safer” from a crash perspective. However, your data should be nailed down, so a crash would actually tell you what’s wrong with your data pretty quickly.
What, though, is the safe Swift way of handling this? We can coerce our objects to optionals and use optional chaining instead:
var streetAddresses = items.map({ $0["address"]?["street"] as? String})
So our first optional operator says to return the object or nil and the second operator says that is should be an optional of type String. This call returns an array of optionals that has this output in our playground:
[nil, nil, {Some "22311 Place Ave."}, {Some "10 Orange Rd."}]
Assuming the following data:
var items = [
["first" : "Billy", "last" : "Bogart", "addr" : ["street" : "111 Main Street"]],
["first" : "Gary", "last" : "Gollum", "addr" : ["street" : "2277 AB Street"]],
["first" : "David", "last" : "Dangerly", "address" : ["street" : "22311 Place Ave."]],
["first" : "Johnny", "last" : "Jones", "address" : ["street" : "10 Orange Rd."]]
]
Notice the first two use the bad addr field and the last two use the correct address field.
For my applications, I think I would prefer to see a crash so I know my data is bad. It’s the server developer’s problem. Am I right? ;-)
Taking Map() Farther
The map() function really goes far beyond this trivial little valueForKeyPath: replacement example. You can really massage your data into any form you want with it. Say for example you wanted to create an transformed array of dictionaries from your array of dictionaries that had some of the same data, but organized differently. For example:
var fullNames = items.map({ ["full_name" : ($0["first"] as? String)! + " " + ($0["last"] as? String)!] })
This returns an array of dictionaries that contain a single key value pair with a key called full_name and value of the first name and last name of each item in the original array concatenated together. The output looks like this in our playground:
[["full_name": "Billy Bogart"], ["full_name": "Gary Gollum"], ["full_name": "David Dangerly"], ["full_name": "Johnny Jones"]]
As you can see, there really are a lot of possibilities for massaging your data structures using map. The tough part is imagining how it might be used and often that just comes from experience. The more you use it, the more obvious the solutions will become.
Swift Is Not So Bad
There are certain complaints about Swift I still have, however, I am finding that it is growing on me. I am starting to have much more success making my code pure Swift–pulling back from my old habits and considering how problems should be solved in this brave new Swift world. It’s getting better and some of the language aspects are actually better than Objective-C. I couldn’t see that forest for the trees just a couple short months ago. Until next time.
Protocols in Swift With Core Data
Sometimes you have a set of objects you want to display in the same form–say, for example, in a table view controller. What if those objects have, by design, nothing in common and nothing to do with each other? This is a case where you can create and conform to a protocol–known in some languages as an interface–to provide a simple way to have each class type provide a display name that can be displayed in your table view controller.
Recently while using this language feature writing Swift code, I ran into a few snags and learned from the process. I figured I would document it in this screencast. It walks you all the way through from project creation, so it’s about 35 minutes.
Here’s what you will learn:
- How to setup CoreData entities in the data model
- How to add a run script action to build your managed object classes using mogenerator
- How to create a protocol in Xcode 6
- How to implement a protocol in the various managed object classes
- How to preload your CoreData store with test objects in code
- How to load each object type generically into a table view controller
And if you want to just cut to the chase, grab the code from github.
Protocols in Swift With Core Data from Skye Road Systems on Vimeo.
The Core Data stack in Swift
Whenever Apple releases a new version of Xcode one of the first things that I do is look at the default templates and see if there are any new or interesting things.
This year, with the release of Swift, there are some pretty radical changes. Yet the Core Data stack initialization code is still the same.
There is nothing wrong with the default template code but there isn’t really anything right about it either. It is far better than it once was but it is still overly verbose and hard to follow.
Therefore, I present my Swift Core Data stack code that I will be using as I grok this language.
Deleting Objects in Core Data
I very rarely speak out against another blog post. I find the resulting argument back and forth draining. However, there are exceptions and one occurred over the weekend.
Brent Simmons has been blogging about his conversion of Vesper to a Core Data application. A recent post of his titled Core Data and Deleting Objects set my teeth on edge. Brent says:
“The best advice I’ve heard about deleting managed objects is to 1) not do it, or 2) do it only at startup, before any references to those to-be-deleted objects can be made.”
I do not know who is giving Brent advice but he must be playing tricks with him or just trying to wind him up. The advice was simple; don’t delete Core Data objects or if you are going to delete them, delete them at launch.
Will that work? Sure. Is it the right answer? Not even close.