WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

How to delete a Core Data object

Table views have a built-in swipe to delete mechanic that we can draw upon to let users delete commits in our app. Helpfully, managed object context has a matching delete() method that will delete any object regardless of its type or location in the object graph. Once an object has been deleted from the context, we can then call saveContext() to write that change back to the persistent store so that the change is permanent.

All this is easy to do by adding three new lines of code to the table view’s commit method. Here's the new method:

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let commit = commits[indexPath.row]
        commits.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)


So, it 1) pulls out the Commit object that the user selected to delete, 2) removes it from the managed object context, 3) removes it from the commits array, 4) deletes it from the table view, then 5) saves the context. Remember: you must call saveContext() whenever you want your changes to persist.

Try running the app now, then swipe to delete a few rows. As you'll see you can delete as many commits as you want, and everything seems to work great. Now try running the app once again, and you'll get a nasty shock: the deleted commits reappear! What's going on?

Well, if you think about it, the app is doing exactly what we told it to do: every time it runs it re-fetches the list of commits from GitHub, and merges it with the commits in its data store. This means any commits we try to delete just get redownloaded again – they really are being deleted, but then they get recreated as soon as the app is relaunched.

This problem is not a hard one to fix, and it gives me a chance to show you another part of NSFetchRequest: the fetchLimit property. This tells Core Data how many items you want it to return. What we're going to do is find the newest commit in our data store, then use the date from that to ask GitHub to provide only newer commits.

First, go to the fetchCommits() method and modify the start of it to this:

@objc func fetchCommits() {
    let newestCommitDate = getNewestCommitDate()

    if let data = try? String(contentsOf: URL(string: "https://api.github.com/repos/apple/swift/commits?per_page=100&since=\(newestCommitDate)")!) {
        let jsonCommits = JSON(parseJSON: data)

We'll be adding the getNewestCommitDate() method shortly, but what it will return is a date formatted as an ISO-8601 string. This date will be set to one second after our most recent commit, and we can send that to the GitHub API using its "since" parameter to receive back only newer commits.

Here is the getNewestCommitDate() method – only three pieces of it are new, and I'll explain them momentarily.

func getNewestCommitDate() -> String {
    let formatter = ISO8601DateFormatter()

    let newest = Commit.createFetchRequest()
    let sort = NSSortDescriptor(key: "date", ascending: false)
    newest.sortDescriptors = [sort]
    newest.fetchLimit = 1

    if let commits = try? container.viewContext.fetch(newest) {
        if commits.count > 0 {
            return formatter.string(from: commits[0].date.addingTimeInterval(1))

    return formatter.string(from: Date(timeIntervalSince1970: 0))

The first of the new pieces of code is the fetchLimit property for the fetch request. As you might imagine, it's always more efficient to fetch as few objects as needed, so if you can set a fetch limit you should do so.

Second, the string(from:) method is the inverse of the date(from:) method we used when parsing the commit JSON. We use the same date format that was defined earlier, because GitHub's "since" parameter is specified in an identical way. Finally, addingTimeInterval() is used to add one second to the time from the previous commit, otherwise GitHub will return the newest commit again.

If no valid date is found, the method returns a date from the 1st of January 1970, which will reproduce the same behavior we had before introducing this date change.

This solution is a good start, but it has a small flaw – see if you can spot it! If not, don't worry: I'll be setting it as homework for you. Regardless, it gave me the chance to show you the fetchLimit property, and you know how much I love squeezing new knowledge in…

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 3.8/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.