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

3 Steps to fetch in Core Data (Swift)

1. Get the managed context:

    let managedObjectContext = (NSApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!

//Change AppDelegate for the name of the class of your Application Delegate

 

2. Set a variable to store the data:

    var contentsOfTransactionFetchRequest = []

3. Fetch the data you need

        let fetchRequest = NSFetchRequest(entityName: “Whatever”)

        contentsOfTransactionFetchRequest = try! managedObjectContext.executeFetchRequest(fetchRequest)

Hope it helps, for me it’s good to have it summarized for later reference!

If you have any feedback I’m at @MarcMasVi

Marc

Working with NSUserDefaults in Swift 2

I was quite pleased to see than in Swift is even easier than in Objective-C. Here is how you do it:

Create a variable that can access them: 

 

    var userDefaults = NSUserDefaults.standardUserDefaults()

 

Add values to dictionary:

 

    userDefaults.setObject(“StringText”, forKey: “KeyInDictionary”)

 

Read values from dictionary:

 

    

    let textuserDefaults.objectForKey(“KeyInDictionary”) as! String

 

 

And that’s in a very simple way how it works. If you want to get into it deeper you can look into the documentation or read this great post

 

If you have any feedback I’m at @MarcMasVi

Marc

Mouse Down (NSEvent in Swift 2)

As I continue adding features for my upcoming app I’m starting to work with NSEvents to add actions to user interaction. I’ve been amazed at how fast is to do this in Swift. 

For instance, detecting where the user presses a button in your window, and then converting it to the coordinate system of a view is extremely easy. Just type the following within your NSView class:

override func mouseDown(theEvent : NSEvent) {

        Swift.print(“Original: \(theEvent.locationInWindow)”)

        let convertedPoint = self.convertPoint(theEvent.locationInWindow, fromView: theEvent.window?.contentView)

        Swift.print(“Tuned: \(convertedPoint)”)

 

    }

Easy as pie!

Feedback, send it @MarcMasVi on Twitter. 

 

Switching NSViewControllers from NSWindowController

This has taken quite some time to crack as there was not that much available information online. 

I wanted a very simple way to change the NSViewController of a window on the fly by using code. 

Screen Shot 2015 12 07 at 18 41 33

The solution I ended up with is quite easy, on the NSWindowController I load the default NSViewController by typing in windowDidLoad():

let viewController = storyboard?.instantiateControllerWithIdentifier(“nsviewcontroller1″) as! NSViewController

        self.window?.contentViewController = viewController

Afterwards, when I want to change NSViewController1 by NSViewController2 i just have a button in my toolbar linked to the following action:

@IBAction func showController2(sender: NSToolbarItem){

        let viewController = storyboard?.instantiateControllerWithIdentifier(nsviewcontroller2) as! NSViewController

        self.window?.contentViewController = viewController

    }

That’s about it, extremely simple, but took me quite a bit to develop. 

As always if you have any feedback I’m at @MarcMasVi

 

Marc

Get NSDate Day, Month or Year in Swift 2.0

Looking for Swift 3.0 version? -> Click here 

Well, having recharged batteries after vacation I’m back into coding!

And yet again I was faced with another simple problem: how to get the day, month or year from a date. 

This is the simpler solution I’ve found in Swift 2:

 

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

let calendar = NSCalendar.init(calendarIdentifier: NSCalendarIdentifierGregorian)

     

 

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

let currentMonthInt = (calendar?.component(NSCalendarUnit.Month, fromDate: NSDate()))!

       

 

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

let currentYearInt = (calendar?.component(NSCalendarUnit.Year, fromDate: NSDate()))!

 

Note that in my code I used NSDate() as the date, this will return today’s date. Also, instead of month or year you could use any of the NSCalendarUnits to retrieve the relevant unit you’re interested in. 

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

 

Marc

Dates & Components in Swift 2.0

Another topic that has been changed in Swift 2.0 is how to work with dates.

I’m digging into this topic for my upcoming app and I’ve found that most documentation on the web refers to Swift 1.2. So here are some snippets to create dates using components:

//CreateDateFromComponents (1st January 2016)

       var newDate = NSDate()

       let newDateComponents: NSDateComponents = NSDateComponents()

       newDateComponents.setValue(1, forComponent: NSCalendarUnit.Day)

       newDateComponents.setValue(1, forComponent: NSCalendarUnit.Month)

       newDateComponents.setValue(2016, forComponent: NSCalendarUnit.Year)

       newDate = NSCalendar.currentCalendar().dateFromComponents(newDateComponents)!

 

//AddToDateFromComponents (1 day, 1 month and 1 year to today)

 

        var newDate = NSDate()

        let newDateComponentsWhereQueryShouldBegin: NSDateComponents = NSDateComponents()

        newDateComponents.setValue(1, forComponent: NSCalendarUnit.Day)

        newDateComponents.setValue(1, forComponent: NSCalendarUnit.Month)

        newDateComponents.setValue(1, forComponent: NSCalendarUnit.Year)

        newDate = NSCalendar.currentCalendar().dateByAddingComponents(newDateComponents, toDate: newDate, options: NSCalendarOptions(rawValue: 0))! 

 

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

 

Marc

 

Evaluate string width and return CGFloat (Swift, OSX)

This morning I’ve been working in a Swift function to detect the width of a given text and return a CGFloat. 

I’ve not found that many examples on the web for OSX, so here you have what I’ve done in all of its glory:

func evaluateStringWidth (textToEvaluate: String) -> CGFloat{

    letfont = NSFont.userFontOfSize(NSFont.systemFontSize())

    let attributes = NSDictionary(object: font!, forKey:NSFontAttributeName)

    let sizeOfText = textToEvaluate.sizeWithAttributes((attributes as! [String : AnyObject]))

    

    return sizeOfText.width

}

 

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

CSV Parser Swift 2

One of the features I’m adding to an upcoming app is the ability to import CSV files. For that purpose I looked around for code already available (and found several options, see below), however none of them compelled me enough so I decided to create my own. 

The main objective was to make it as simple as possible and, of course, coded in Swift 2. Note however that I’m still learning so if you would have any suggestions / feedback send them my way! Here it is in all of its glory:

//

//  CSVImporter.swift

//  Controller

//

//  Created by Marc on 5/8/15.

//  Copyright (c) 2015 MMV Solucions S.L. All rights reserved.

//

 

import Cocoa

 

class CSVImporter: NSObject {

 

    var columnDelimiter = “,”

    var textDelimiter = “\””

    var rowDelimiter = “\n”

    var doesItHaveHeader = true

    var rowsFromString : Array<String> = []

    var finalParsedCsv : Array<Array<String>> = []

    

    

 

    

    func retrieveCsvFileAndReturnRows(path path: String ) -> Array<Array<String>>? { //Main

        

        let stringToParse: String?

        do{

            stringToParse = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)

        } catch _ {

            stringToParse = nil

        }

        var unwrappedStringToParse=“”

        

        if (stringToParse == nil) { return nil } else {

            unwrappedStringToParse = stringToParse! }

        

        //Cleaning string

        unwrappedStringToParse = stringToParse!.stringByReplacingOccurrencesOfString(“\r”, withString: “\n”)

        unwrappedStringToParse = unwrappedStringToParse.stringByReplacingOccurrencesOfString(“\n\n”, withString: “\n”)

        

        //Storing by rows

        rowsFromString = unwrappedStringToParse.componentsSeparatedByString(rowDelimiter)

        

        //Removing header

        if (doesItHaveHeader == true){

            rowsFromString.removeAtIndex(0)

        }

        

        //Converting and adding rows

        for iteratorString in rowsFromString {

            

            if(iteratorString.rangeOfString(textDelimiter) != nil){ //We have detected double quotes

                let arrayContainingDoubleQuotes = iteratorString.componentsSeparatedByString(columnDelimiter)

                var newArrayAccountingForQuotes : Array <String> = []

                var tempArrayContainingNewWord : Array <String> = []

                var inDoubleQuoteLoop = false

                var newStringFromSplittedWord = “”

                for stringToTestForDoublequotes in arrayContainingDoubleQuotes{

                    if stringToTestForDoublequotes.rangeOfString(textDelimiter) != nil || inDoubleQuoteLoop == true {

                        if stringToTestForDoublequotes.rangeOfString(textDelimiter) != nil && inDoubleQuoteLoop == false {

                            tempArrayContainingNewWord.append(stringToTestForDoublequotes)

                            inDoubleQuoteLoop = true

                        }else{

                            tempArrayContainingNewWord.append(stringToTestForDoublequotes)

                            newStringFromSplittedWord = “”.join(tempArrayContainingNewWord)

                            newArrayAccountingForQuotes.append(newStringFromSplittedWord)

                            //Maybe add here option to remove “

                            inDoubleQuoteLoop = false

                        }

 

                    }else{ //No double quotes found and not in the middle of text, add to new array

                     newArrayAccountingForQuotes.append(stringToTestForDoublequotes)

                    }

                }

                finalParsedCsv.append(newArrayAccountingForQuotes)

            }else{

                finalParsedCsv.append(iteratorString.componentsSeparatedByString(columnDelimiter))

            }

            

        }

        

        //Final cleaning

        var row = 0

        for iteratorForFinalCleaning in finalParsedCsv{

            var column = 0

            for _ in iteratorForFinalCleaning{

                //Get the text of these coordinates

                var tempStringToRemoveCommas = finalParsedCsv[row][column]

                if (tempStringToRemoveCommas.rangeOfString(textDelimiter) != nil){

                //Do the needed changes into the text

                tempStringToRemoveCommas = tempStringToRemoveCommas.stringByReplacingOccurrencesOfString(textDelimiter, withString: “”)

                //Add result back to the arrayOfParsedContent

                finalParsedCsv[row].insert(tempStringToRemoveCommas, atIndex: column)

                }

                column++

            }

            row++

        }

        

        returnfinalParsedCsv

    }

    

 

}

 

 

Remember I’m still on my Swift beginnings, if you want other options check out SwiftCSV or this post