Denarius 1.6 & the slippery bug

This last couple of months I’ve been hard at work on two new projects, the first of which will be released fairly soon! But, today I wanted to write about something else: CoreData Concurrency.

Since the release of Denarius about a year ago I’ve been regularly improving the personal finance app with new features and, of course, bug fixes. However there was this one bug that kept popping up in crash logs but that I was unable to track down. I knew it had something to do with Core Data but that’s the extend of it. 

CoreData in Denarius is implemented with two Managed Object Context, one of them being the background one for complex tasks and a second one for standard operation (as explained in this post).  So, everything was supposedly working as intended. 

However, after way too many hours I saw what was going on: I was doing a change in the main thread with information computed on the background thread… So, how did I solve it? Using objectID of course, the only safe way to transfer objects between threads. 

So instead of:

mainThreadObject.attributeX = computedThreadObjectInBackgroundQueue.attributeX

Now I had (and remember this piece of code is being executed in the background):

let transactionObjectId = mainThreadObject1.objectID
let typeObjectId = computedThreadObject2InBackgroundQueue.objectID
DispatchQueue.main.async { //Here I’m calling the main thread and push the complex background computation to the right object
      (self.managedObjectContext.object(with: transactionObjectId) as! object1).attributeX = (self.managedObjectContext.object(with: typeObjectId) as! object2).attributeX

}

A bit longer, but did the trick! This improvement will ship very soon with the new Denarius 1.6 release. 

Questions / comments? I’m at @MarcMasVi 

Marc

Shoe Dog: A Memoir by the Creator of Nike

Just finished “Shoe Dog: A Memoir by the Creator of Nike” and it’s great:  well written and refreshingly honest.

Even if you’re not into business books, I believe this one is worth your time. 

Bill Gates could not have said it better in his book review:

“Shoe Dog, Phil Knight’s memoir about creating Nike, is a refreshingly honest reminder of what the path to business success really looks like. It’s a messy, perilous, and chaotic journey riddled with mistakes, endless struggles, and sacrifice. In fact, the only thing that seems inevitable in page after page of Knight’s story is that his company will end in failure.” Source

 

Marc

Get Date Day, Month or Year in Swift 3.0

Just a quick update to show how to get Date Day, Month or Year in Swift 3

//Here I’m creating the calendar instance that we will operate with:

let calendar = NSCalendar.init(calendarIdentifier: NSCalendar.Identifier.gregorian)

     

 

//Now asking the calendar what month are we in today’s date:

let currentMonthInt = (calendar?.component(NSCalendar.Unit.month, from: Date()))!

       

 

//Now asking the calendar what year are we in today’s date:

let currentYearInt = (calendar?.component(NSCalendar.Unit.year, from: Date()))!

 

Hope this proves useful.

If you would have any suggestions on how to improve reach me @MarcMasVi in Twitter. 

 Marc

Blogging about developing an app: Denarius

Roughly two years ago I started blogging about the challenges of developing a new Mac app. I decided to do so after reading Brent Simmons great series on Vesper development. I thought it was a great way to 1. structure my thoughts and 2. help the community. 

It’s been one of the most fun times I’ve had in years. The kick I get out of creating something from nothing* is not easily found anywhere else.

Also worth mentioning is the Mac community: all fellow Mac developers I engaged with were very helpful and responsive, I’m extremely thankful for that. Thank you. 

Enough rambling, about the app I’ve been -indirectly- blogging about: It’s called Denarius and it’s a Personal finance Mac app. For years I controlled my personal finances with excel; existing Mac apps had a lot to offer but they required a lot of micromanagement as well.

My goal for Denarius was simple: the app should tell you all you need to know with minimal effort.

I hope you like it, you can know all about it here. And you can get in touch with me via Twitter at @MarcMasVi

Will update you on how the app does and what I will be working on next. 

 

Marc 

* leveraging the awesome work of Apple developers who worked on all the frameworks I use. 

Simple Animations on macOS (Swift 3)

If you’ve ever coded for iOS you’ll most likely be familiar with the UIView animateWithDuration function. Wouldn’t it be great if there would be an OSX equivalent?

Well, there sure is, just type the following:

        NSAnimationContext.runAnimationGroup({_in

            //Indicate the duration of the animation

            NSAnimationContext.current().duration = 5.0 

            //What is being animated? In this example I’m making a view transparent

            someView.animator().alphaValue = 0.0 

        }, completionHandler:{ 

            //In here we add the code that should be triggered after the animation completes.

            print(“Animation completed”)

        })

 

That’s it, you’re good to go! Questions / comments? I’m at @MarcMasVi 

 

Marc

 

Synchronizing Main and Background Core Data Threads (Swift 3)

Let’s say we have two different managedObjectContext (with one persistentStoreCoordinator). 

The first one is used across the app for most quick fetches:

var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)

 

        mainManagedObjectContext.persistentStoreCoordinator = coordinator

 

 

And the second, running in the background, for the queries that take a long time:

var backgroundManagedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType)

        backgroundManagedObjectContext.persistentStoreCoordinator = coordinator

 

When they are initialized both contain the same data. However once changes are applied to one of them -in this example the main- like adding, changing or deleting rows, the other will not know -in this example the background/private one-.

 

Screen Shot 2016 11 27 at 13 19 12

 

Therefore if we add objects to the main managedObjectContext, when we fetch the backgroundManagedObjectContext we will not get them. 

How do we fix this? Well first we have to save the changes of the objectContext that was modified. We do so by adding once we’ve finalized the changes:

       //Commit changes

        do {

            try managedObjectContext.save()

        }catch{

            print(“ERROR: Cound not save Core Data”)

        }

        

At this point we have saved the changes in the Persistent Store. We still have to ask the backgroundObjectContext to get them from the persistent store thought. For that we will use the automatic notification “NSManagedObjectContextDidSave”.

In the class where the backgroundThread is contained we will add an observer for the notification (note that we’re passing as object the context that was modified):

//Handle changes in core data for background thread

        NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.handleMainCoreDataChangeInBackgroundManagedContext(notification:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: managedObjectContext)

    }

And then we will add the function that will syncronize the backgroundThread, in this example: 

func handleMainCoreDataChangeInBackgroundManagedContext(notification: Notification){

        managedObjectContextBackgroundThread?.mergeChanges(fromContextDidSave: notification)

    }

That’s it! Now when you query the background thread you’ll get the same information as you have in the main one. 

You can read more about NSManagedObjectContext in Apple Docs

 

Questions / comments? I’m at @MarcMasVi 

 

Marc

 

 

Note: using two contexts is very powerful when used in combination with dispatchqueues

       DispatchQueue.global().async {

            //Query here in background context & save if applicable

            DispatchQueue.main.async {

                //Refresh UI & query main context & save if applicable

            }

        }

 

Are we (NSViewController view) the First Responder?

In some cases a class may want to know if it’s the first responder before triggering an action.

For instance if several loaded View Controller classes are listening for the same notification, how can they know which one should trigger the action? Well… they should ask their view. 

In this case a NSTableView class is asking if it’s currently the first responder:

        if (self.view.window?.firstResponder == self.tableView){

            triggerFunctionHere()

        }

And that’s it 🙂

Questions / comments? I’m at @MarcMasVi 

Marc

Undo functionality in Core Data (Swift 3)

If you’re developing a Core Data based application for Mac, wouldn’t it be great if you could add undo support?

Well, turns out that is a couple of lines away. Follow the simple steps:

1. Make sure your managedObjectContext has an undo manager, without it Core Data can’t keep track of the changes:

         managedObjectContext?.undoManager = UndoManager() 

2. In the viewController where you should handle the undo operation just add:

      func undo(_ sender: AnyObject?){

  

        coreDataHelper.managedObjectContext.undoManager?.undo()

 

        refreshTable() //If applicable (for instance if you don’t use bindings)

        re-fetch the information and reload the table. This is what this

        function does in my code

 

      }

And that’s it, now you have full undo functionality! You’ll see how in the menus Undo no longer appears greyed out.

Questions / comments? I’m at @MarcMasVi 

Marc

Sorting Multi Dimensional Array (Swift 3)

Hello all, 

This one I’ve found specially useful when working with Core Data fetched arrays. 

Let’s say that we want to sort the result of a fetch request based on the value of the field “gold”, we would therefore do the following:

let dwarfGoldBags = … //Contains the result of a fetch request with one of the fields named “gold” and being an integer.


 

We will now proceed to sort the array and store it in sortedGoldArray:

let sortedGoldArray = dwarfGoldBags.sorted { ($0.goldas Int) > ($1.goldas Int) } 

 

If instead of core data you have a multi-dimensional array it would be as easy as:

let sortArray = originalArray.sorted { ($0.[0] as Int) > ($1.[0] as Int) } 

 

In this case we’re comparing the values stored in the first value of the subArrays. 

Questions / comments? I’m at @MarcMasVi 

Marc