Dates & Components in Swift 3.0

The way we work with dates has changed in Swift 3, the change makes it’s way simpler then before. Let’s look at an example:

//CreateDateFromComponents (1st January 2017)

            var newDate = Date()

            let newDateComponents = DateComponents(calendar: Calendar.current, timeZone: nil, era: nil, year: 2017, month: 1, day: 1, hour: nil, minute: nil, second: nil, nanosecond: nil, weekday: nil, weekdayOrdinal: nil, quarter: nil, weekOfMonth: nil, weekOfYear: nil, yearForWeekOfYear: nil)

            newDate = Calendar.current.date(from: newDateComponents)!

 

Hope this proves useful. If you would have any suggestions on how to improve you know where to reach me, @MarcMasVi in Twitter.

 

Marc

 

Testing launch experience for a Mac app

In iOS it’s quite easy, you just delete the app and all of it’s data is removed as well. But how do you do it in OSX? Well, you should remove:

~/Library/Application Support/<YOUR OSX APP BUNDLE NAME>/

for example, by default should be:

~/Library/Application Support/com.yourcompany.yourapp/

And this is it! I suggest you do a Project -> Clean Build folder (to see this option you will have to press Alt while in the Porject menu) afterwards, just to be sure. 

Questions / comments? I’m at @MarcMasVi 

Marc

 

Scheduled notifications in macOS

Notifications are a very useful addition to macOS applications, when done right can help inmensly. 

Here’s how you create scheduled and immediate notifications. Let’s start with the immediate ones:

func triggerNotification() -> Void {

    let notification = NSUserNotification()

    notification.title = “titleOfNotification”

    notification.informativeText = “whateverTextYou WantToAdd”

    notification.soundName = NSUserNotificationDefaultSoundName

    NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification)

}

This will trigger a notification the moment you execute it, if however you would like to schedule a notification for a later date you can do:

func showNotification(atDate: NSDate) -> Void {

    let notification = NSUserNotification()

    notification.title = “It’s MONTH”

    notification.informativeText = “Time to check your finances!”

    notification.soundName = NSUserNotificationDefaultSoundName

    notification.deliveryDate = NSDate().dateByAddingTimeInterval(5.0)

    //notification.deliveryDate = getDateOfNextNotification()

    NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification(notification)

}

In this case you would be showing the notification after 5 seconds, more useful though is to plan it for a later date, like you can see in my commented code. The getDateOfNextNotification function simply returns the NSDate where I would like the notification to trigger. 

If you plan to use this, for instance in App Delegate, you may want to check if you have already scheduled notification to avoid duplicates. You can do the following:

func scheduleUpcomingAlertNotification() -> Void {

    let pipeOfNotifications = NSUserNotificationCenter.defaultUserNotificationCenter().scheduledNotifications.count

    if( pipeOfNotifications > 0){

        return

    }else trigger the function

Questions / comments? I’m at @MarcMasVi 

Marc

Copy one or multiple NSTableView rows, Swift

So here’s a simple yet tricky one: you’ve created your NSTableView but now you would like to allow a user to copy to the clipboard one, or a couple of rows. How do you do it?

1. Implement the function copy (func copy(sender: AnyObject?){}), do not confuse with the method for duplicating an object

 2. Get the index set from the tableView selection and retrieve the relevant rows from your dataSource. From there is just a matter of composing the text to copy into the pasteboard. 

Here’s my code structure, implemented in my NSTableViewController:

func copy(sender: AnyObject?){

        

        var textToDisplayInPasteboard = “”

        let indexSet = tableView.selectedRowIndexes

        for (_, rowIndex) in indexSet.enumerate() {

            var iterator: CoreDataOjectType

            iterator=tableDataSource.objectAtIndex(rowIndex)

            textToDisplayInPasteboard = (iterator.name)! 

        }

        let pasteBoard = NSPasteboard.generalPasteboard()

        pasteBoard.clearContents()

        pasteBoard.setString(textToDisplayInPasteboard, forType:NSPasteboardTypeString)

        

    }

This will also automatically enable the Edit -> Copy (Command + C) menu, that would be disabled -grayed out- without this code. 

Questions / comments? I’m at @MarcMasVi 

Marc

Easy Core Data CSV Exporter in Swift

A new app I’m working on has a Core Data back end and I wanted to implement a quick way to export all the entities into a CSV file and dump it into the Desktop. 

Here are the snippets to do it:

1. Make sure you get the NSObjects you want to export (in this case I use a function that will return an array with the fetched NSObjectSubclass Transaction)

   private func provideAllTransactions() -> Array<Transaction>{

        let fetchRequest = NSFetchRequest(entityName: “Transaction”)

        fetchRequest.sortDescriptors = [NSSortDescriptor(key: “date”, ascending: false), NSSortDescriptor(key: “concept”, ascending: true)]

        return try! managedObjectContext.executeFetchRequest(fetchRequest) as! Array<Transaction>

    }

2. Convert to text, properly separating by commas and lines

    private func convertTransactionsToCsvString(transactions: Array<Transaction>)->String{

        var result = “HEADER 1, HEADER 2, HEADER 3, \r”//Headers

        

        for transactionIterator in transactions{ //Data

            result = result + “\”” + (transactionIterator.accountItBelongsTo?.name)! + “\”” + “,”

            result = result + “\”” + ((transactionIterator.date)?.description)! ?? NSDate().description

            result = result + “\”” + “,” + “\”” + (transactionIterator.concept)! + “\””

            result = result + “\”” + “\r”

        }

        

        return result

    }

3. Save to a path 

    func exportAllToCsv() -> Bool{

        

        let contentsToWrite = convertTransactionsToCsvString(provideAllTransactions())

        

        //Select path

        let path = “/Users/USER_NAME/Desktop/csvTest.csv”

        //Try to save it

        do {

            try contentsToWrite.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)

        }catch{

            print(“ERROR: Export could not be saved in %”, path)

        }

        

        return true

 

    }

Note that in this example the path is hardcoded to the desktop of the user named USER_NAME, you should have the user choose where he wants to save it or you can hardcode a location in your disk. 

If you would have a NSDictionary it would be almost the same but starting at point 2 with the dictionary results. 

Questions / comments? I’m at @MarcMasVi

Marc

 

PS. Here is how you would have the path be selected by the user:        

 

    privatefunc userToChooseAFileInModalPannel() -> String?{

        let pannel: NSOpenPanel = NSOpenPanel()

        pannel.canChooseDirectories = true

        pannel.canChooseFiles = false

        pannel.allowsMultipleSelection = false

        pannel.runModal()

        

        return pannel.URL?.path

    }

 then in point 3 you would do 

//Select path

        let path = userToChooseAFileInModalPannel() + “/test.csv”


Back to coding!

You may have noticed a steep drop in post frequency this last couple of months. The reason is that I just got married and well… I code and write this blog on my spare time and, with planning and all, have not had much of that this last months. 

Should be back to normal in a weeks time! I’m enjoying a lot the honey moon, but damn it I also miss coding!

Is it too late for me to be saved? 

Working with localized numbers – NSNumberFormatter Swift 2

In my case, I’m working on a csv importer and I wanted to get from the system the decimal and thousand delimiters. 

This is the way I do it, a workaround sure but works great:

var thousandDelimiter = NSNumberFormatter.localizedStringFromNumber(NSNumber(double: 1234), numberStyle: NSNumberFormatterStyle.DecimalStyle)


thousandDelimiter = thousandDelimiter.substringWithRange(thousandDelimiter.startIndex.advancedBy(1)…thousandDelimiter.startIndex.advancedBy(1))


 

var commaDelimiter = NSNumberFormatter.localizedStringFromNumber(NSNumber(double: 1.02), numberStyle: NSNumberFormatterStyle.DecimalStyle)

 

commaDelimiter = commaDelimiter.substringWithRange(commaDelimiter.startIndex.advancedBy(1)…commaDelimiter.startIndex.advancedBy(1))


Again, documentation in this case is quite good, find more here

Marc

Using NSValueTransformers (Value Transformer) Swift 2.0

So here’s a tricky one, on my upcoming app I sometimes use View-Based TableViews.

Mostly, it works like magic, but sometimes you need to use a Value Transformer in the binding to allow the table to understand how to display something. In this example, I needed to convert a NSNumber to a String (and back!). Here’s how you do it:

1. Create a NSValueTransformer subclass (here’s mine for your reference):

import Cocoa

 

class TransformerNSNumberToString: NSValueTransformer {

 

    override class func transformedValueClass() -> AnyClass { //What do I transform

        return NSNumber.self

    }

    

    override class func allowsReverseTransformation() -> Bool { //Can I transform back?

        returntrue

    }

    

    override func transformedValue(value: AnyObject?) -> AnyObject? { //Perform transformation

        guard let type = value as? NSNumber else { return nil }

        return type.stringValue

        

    }

    

    override func reverseTransformedValue(value: AnyObject?) -> AnyObject? { //Revert transformation

        guard let type = value as? NSString else { return nil }

        return NSNumber(double: type.doubleValue)

    }

}

2. In the App Delegate, in my case I put it inside applicationDidFinishLaunching you add (yes, it’s weird but true!):

func applicationDidFinishLaunching(aNotification: NSNotification) {

        NSValueTransformer.setValueTransformer(TransformerNSNumberToString(), forName: “TransformerNSNumberToString”) //

    }

3. In the binding you add the Value Transformer needed!

Screen Shot 2016 02 07 at 21 32 28

Screen Shot 2016 02 07 at 21 32 36

 

That’s it! A great post explaining this in more detail is NSHipster, it’s the best source I found out there apart from Apple docs. 

Questions / comments? I’m at @MarcMasVi

Marc