Category: macOS

April 16th, 2017 by admin

If you’re creating a macOS program, you may want to display a dialog box on the screen to alert the user of something, such as an error message of some kind. The simplest way to create a dialog is to use the NSAlert class like this:

        let myAlert = NSAlert()
        myAlert.messageText = "Message text"
        myAlert.informativeText = "Informative text"
        myAlert.runModal()

If you create a push button on a window and store the above code in an IBAction method for This code creates a simple dialog that looks like this:

The messageText property defines the bold text and the informativeText property defines the text that appears underneath.

As an alternative to displaying a modal dialog, you can also display a sheet instead by using this code:

        let myAlert = NSAlert()
        myAlert.messageText = "Message text"
        myAlert.informativeText = "Informative text"
        myAlert.beginSheetModal(for: self.view.window!, completionHandler: nil)

This creates a sheet like this:

A simple dialog that displays a message is fine. When the user wants to dismiss the dialog, he or she can just click the OK button. However in many cases, you may want to add up to three buttons on a dialog with custom text. To do that, you need to use the addButton method like this:

        myAlert.addButton(withTitle: "Save")
        myAlert.addButton(withTitle: "Delete")
        myAlert.addButton(withTitle: "Cancel")

To determine which button the user clicked, you need to use a switch statement. If you created a modal dialog using the runModal() method, your switch statement might look like this:

        switch myAlert.runModal() {
            case NSAlertFirstButtonReturn: print ("Save")
            case NSAlertSecondButtonReturn: print ("Delete")
            case NSAlertThirdButtonReturn: print ("Cancel")
            default: print ("Nothing")
        }

So if you placed a push button on a window, and created an IBAction method to display a dialog by clicking this push button, your entire code might look like this:

    @IBAction func showAlert(_ sender: NSButton) {
        let myAlert = NSAlert()
        myAlert.messageText = "Message text"
        myAlert.informativeText = "Informative text"
        
        myAlert.addButton(withTitle: "Save")
        myAlert.addButton(withTitle: "Delete")
        myAlert.addButton(withTitle: "Cancel")
        
        switch myAlert.runModal() {
            case NSAlertFirstButtonReturn: print ("Save")
            case NSAlertSecondButtonReturn: print ("Delete")
            case NSAlertThirdButtonReturn: print ("Cancel")
            default: print ("Nothing")
        }
    }

To determine which button the user clicked if you created a sheet, your switch statement would look slightly differently:

        myAlert.beginSheetModal(for: self.view.window!, completionHandler: { (returnCode) -> Void in
            switch returnCode {
                case NSAlertFirstButtonReturn: print ("Save")
                case NSAlertSecondButtonReturn: print ("Delete")
                case NSAlertThirdButtonReturn: print ("Cancel")
                default: print ("Nothing")
            }
        })

If you created a push button on a window with an IBAction method to open a sheet, your entire IBAction method code might look like this:

@IBAction func showAlert(_ sender: NSButton) {
        let myAlert = NSAlert()
        myAlert.messageText = "Message text"
        myAlert.informativeText = "Informative text"
        
        myAlert.addButton(withTitle: "Save")
        myAlert.addButton(withTitle: "Delete")
        myAlert.addButton(withTitle: "Cancel")

        myAlert.beginSheetModal(for: self.view.window!, completionHandler: { (returnCode) -> Void in
            switch returnCode {
                case NSAlertFirstButtonReturn: print ("Save")
                case NSAlertSecondButtonReturn: print ("Delete")
                case NSAlertThirdButtonReturn: print ("Cancel")
                default: print ("Nothing")
            }
        })

    }

By using the NSAlert class, you an easily create and display dialogs as modal dialog boxes or as a sheet. You an also customize the number of buttons (up to three) and retrieve which button the user clicked on.

Posted in Algorithms, macOS, User Interface

March 26th, 2017 by admin

One type of controller you can add to a macOS project storyboard is a page controller. The main purpose of the page controller is to display the contents of two or more view controllers that users can swipe left and right like swiping through pages in an e-book.

To use a page controller, you need to add a page controller to a storyboard. Next, you need to create additional view controllers that are completely separate from the storyboard (not connected to any existing storyboard scenes through segues). These view controllers will only appear within the page controller. You must then give each of these view controllers a unique identifier (name).

To create a unique identifier for each view controller, click on that view controller and then choose View > Utilities > Show Identity Inspector to open the Identity Inspector for that view controller.

Click the blue icon in the top, middle of the view controller window. Then click in the Storyboard ID text field in the Identity Inspector pane and type a descriptive name.

This name can be anything you ant but you’ll refer to this descriptive name later when making the view controller appear inside the page controller.

Next, you must create a Swift class file for your page controller. To do this you’ll need to create a new class file and make sure its subclass is NSPageController. The name can be arbitrary but you’ll need to remember this name when connecting it to the page controller in the storyboard.

Now click on the page controller in your storyboard, click on the blue icon in the top, middle of the Page Controller, and choose View > Utilities > Show Identity Inspector. The Identity Inspector pane appears. Click in the Class popup menu and choose the name you created for the page controller class file.

At this point, you’ve created a page controller and two or more view controllers that are separate from he rest of your storyboard. Now you’ll need to start writing Swift code.

Start by defining your page controller Swift file as an NSPageControllerDelegate. So if you named your Swift class file to control the page control as MyPageController, you’ll need to edit this file so the class heading looks like this:

class MyPageController: NSPageController, NSPageControllerDelegate {

Underneath this class file heading, create an array. The number of items in this array must be equal to the number of view controllers you want to display inside the page controller. So if you wanted to display three view controllers in the page controller, you might create an array with three arbitrarily named items like this:

var myViewArray = ["one", "two", "three"]

Inside the viewDidLoad function, you need to define the class file as its own delegate, set the arrangedObjects property to the name of your array, and define a transitionStyle as either:

  • .horizontalStrip
  • .stackBook
  • .stackHistory
    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self
        self.arrangedObjects = myViewArray
        self.transitionStyle = .horizontalStrip
    }

The transitionStyle property defines how the page controller displays the view controllers.

Now you need to add three additional functions to this page controller Swift class file:

   func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
        
        switch identifier {
        case "one":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page01") as! NSViewController
        case "two":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page02") as! NSViewController
        case "three":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page03") as! NSViewController
        default:
            return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
        }
    }
    
    func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
        return String(describing: object)
        
    }
    
    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        self.completeTransition()
    }

The first function uses a switch statement that uses the strings (“one”, “two”, and “three”) that are stored in the array, which is stored in the page controller’s arrangedObjects property. This switch statement links each array item to a specific view controller in the storyboard.

Remember, these three view controllers are not connected to any part of the storyboard but can be retrieved using their Storyboard ID.

The second function displays the view controller in the page controller.

The third function ends the transition when the user swipes left or right.

The complete page controller Swift class file contents should look like this:

import Cocoa

class MyPageController: NSPageController, NSPageControllerDelegate {
    
    var myViewArray = ["one", "two", "three"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        delegate = self
        self.arrangedObjects = myViewArray
        self.transitionStyle = .stackBook
    }
    
    func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
        
        switch identifier {
        case "one":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page01") as! NSViewController
        case "two":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page02") as! NSViewController
        case "three":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page03") as! NSViewController
        default:
            return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
        }
    }
    
    func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
        return String(describing: object)
        
    }
    
    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        self.completeTransition()
    }
    
}
Sample NSPageController example

Posted in macOS, User Interface

March 13th, 2017 by admin

If you need to run one type of animation after another in macOS, Swift provides a simple way to do this where the code looks like this:

        NSAnimationContext.runAnimationGroup({ (context) -> Void in
               // First animation code here
        }, completionHandler: { () -> Void in
              // Second animation code here          
        })

By itself, this runAnimationGroup code does nothing. What you need to do is put your animation code within the first set of curly brackets and when that first animation completes, then you can run a second set of animation if you wish.

Suppose you want to rotate an item such as a label and when it’s done rotating, flip it back to its original position. First, create a label and an IBOutlet such as:

@IBOutlet weak var lblMessage: NSTextField!

Once you have an IBOutlet to represent a label on the user interface, you can rotate it using this code:

    @IBAction func animateMe(_ sender: NSButton) {
        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            context.duration = 5
            lblMessage.animator().frameRotation = 45
        }, completionHandler: { () -> Void in
            self.lblMessage.animator().frameRotation = 0
        })
    }

Thea love code takes five seconds to rotate a label (lblMessage) 45 degrees. When it’s completed, it changes the label’s rotation back to 0 again.

While this simple example shows how to rotate an item, the more important lesson is to see how the runAnimationGroup lets you combine two different types of animations where the second animation runs after the first animation completes. Any time you need to run two different types of animation back to back, use the runAnimationGroup structure.

Posted in Algorithms, macOS

March 6th, 2017 by admin

If you want to make an item on the user interface appear to fade away and reappear again, you can use something called the animator() method. Essentially all you have to do is create an IBOutlet for a user interface item (such as a button or label) and then apply the animator() method along with defining the alphaValue property to 0 (completely invisible) or 1 (completely visible).

Of course, if you assign a user interface item’s alphaValue property to 0, it will suddenly disappear, so that’s why you need to create a delay effect using the following code:

NSAnimationContext.current().duration = 3

This simply tells code to delay the animator() action by three seconds (or whatever number you assign to the duration property.

Create a simply macOS project using storyboards and place a label and a push button anywhere on the view. Create IBOutlet for the label like this:

@IBOutlet weak var lblMessage: NSTextField!

Now create an IBAction method for the push button (call it AnimateMe) and fill it with Swift code such as:

    @IBAction func animateMe(_ sender: NSButton) {     
        if lblMessage.animator().alphaValue == 1 {
            NSAnimationContext.current().duration = 3
            lblMessage.animator().alphaValue = 0
        } else {
            NSAnimationContext.current().duration = 3
            lblMessage.animator().alphaValue = 1
        }
    }

This code simply checks what the alphaValue of the label might be. If its value is 1 (completely visible), then it slowly fades the label away in three seconds and sets its alphaValue property to 0. This creates a gradual fade out visual effect.

If the label’s alphaValue property is already 0, then the above Swift code takes three seconds to slowly set the alphaValue to 1, which creates a fade in visual effect.

Obviously there’s more to animation using the animator() method but this can get you started in seeing how simple it can be to create animation in a macOS program.

Posted in Algorithms, macOS, User Interface

February 27th, 2017 by admin

As much as Apple tries to make programming easier, the complexity of programming usually means Apple’s efforts actually wind up making programming harder. In the early days, programming was easy for anyone to master using a simple tool like HyperCard, which helped pave the way for visual interface design tools known as rapid application development (RAD) such as Visual Basic.

When Apple abandoned HyperCard, they offered Xcode in its place, which is a professional tool that novices will likely find way too intimidating. On top of trying to learn Xcode, you also have to learn a programming language such as Objective-C (way too confusing) or Swift, which is much easier to learn.

The huge problem with Swift isn’t the language but working with the cocoa frameworks that form the foundation of macOS, iOS, tvOS, and watchOS. You need to understand object-oriented programming along with protocols, and delegates. If all this sounds confusing, it is.

Perhaps one of the clumsiest solutions for solving problems lies with Core Graphics, Apple’s software framework designed to make animation possible. Learning to animate objects in a program means writing tedious Swift code to do the simplest things. Fortunately, there’s a tool that automates much of this process.

Called Core Animator, this program (ranging in cost up to $100 depending on the sales the company may offer at the moment) lets you visually animate objects using graphic files and timelines. Once you create the animation in Core Animator, you can export it into a Swift or Objective-C class file to add into a macOS or iOS project.

Because Core Animator lets you visually design animation and see it work, you don’t have to fumble with creating animation using mathematical formulas in Swift or Objective-C. Just as in the old days when programmers used to hand code user interfaces by writing commands, so does Core Graphics require you to write exhaustive Swift or Objective-C code to create animation.

RAD development tools let you design user interfaces visually and connect it to code. Core Animator lets you design animation visually and create code to add to an Xcode project.

Once you try Core Animator, you’ll never want to go back to hand-coding animation again in Swift or Objective-C because it’s too painful and tedious. Just watch the video below to see how simple it can be to use Core Animator.

While every project can use animation in its user interface, not everyone needs a program like Core Animator. However, animation can make your program stand out and add a little extra polish to your program and that may be worth the cost of Core Animator all by itself.

Posted in iOS, macOS, Programming

February 24th, 2017 by admin

A Split View Controller can display two or more views side by side. Separating the views is a divider that the user can drag back and forth to widen shrink a view. There are two ways to change the appearance of this divider:

  • Choose a style
  • Choose a color

The divider style can appear as Thick, Thin, or Pane Splitter. Strangely, the Thick and Pane Splitter styles look nearly identical with the only difference being that you can change the color of a Thick divider but not a Pane Splitter divider.

To choose a divider style, open the Document Outline pane and click on the Split View.

Next, open the Attributes Inspector pane by choosing View > Utilities > Show Attributes Inspector. In the Style popup menu, choose the style you want for your divider.

Changing the color of the divider is a bit stranger and trickier. Open the Document Outline pane and click on Split View. Now open the Identity Inspector pane by choosing View > Utilities > Show Identity Inspector.

Look for the User Defined Runtime Attributes category and click on the + icon. This creates a generic row of data listing keyPath, Boolean, and a check mark.

Double-click on keyPath and change this text to dividerColor and press Return.

Under the Type column, click the popup menu and change Boolean to Color.

Under the Value category, click the popup menu that appears there and choose a color.

If you chose a Thick or Thin style (not a Pane Splitter) and defined a color, run your project and you should see your chosen divider style and color appear in the split view.

 

 

Posted in macOS, User Interface

February 18th, 2017 by admin

One of the reasons why artificial intelligence (AI) failed during the early days was because it required humans to program intelligence into a program. That meant exhaustively writing instructions for every possible outcome.

One of the earliest and more limited successes of AI were expert systems that consisted of a series of if-then rules to mimic the thinking process of a human expert. The reason why expert systems worked was because they could tackle a narrow niche with limited and known variables. The reason why expert systems ultimately failed is because they couldn’t advance beyond narrow niches and required humans to exhaustively write if-then rules for every possibility.

Even worse, when conditions changed, human programmers had to go back into the expert system to reprogram it and update it. This constantly meant consulting with a human expert and a human programmer, which made the expert system cumbersome to modify to the point where it wasn’t worth it at all.

That’s all changed with machine learning. The whole idea behind machine learning is to let a program teach and update itself. Not only is this far faster, but it’s far more accurate allowing the program to adapt to changing conditions. If you’re interested in machine learning with Swift, download the open source, Swift AI library.

This Swift AI library lets you create neural networks for both macOS and iOS. By incorporating machine learning in your apps, you can create more adaptive video games or smarter programs that can recognize handwriting or user behavior.

Trying to create machine learning tools on your own in Swift is possible, but clumsy. It’s so much easier to use a tested machine learning framework instead, so that’s why you might want to experiment with Swift AI.

As Swift gains popularity, it’s likely that others will create machine learning frameworks for Swift but until that day comes when we can choose from a variety of machine learning tools, Swift AI offers the best way to experiment with machine learning using Swift.

At the very least, dig through the sample programs in the Swift AI library and give yourself a rudimentary understanding of how machine learning works and how to implement it in Swift.

To download the Swift AI library for adding machine learning to iOS and macOS programs, click here.

 

Posted in Algorithms, iOS, macOS

February 3rd, 2017 by admin

In any programming language, you can choose arbitrary names for your functions and parameters. For example, you could create a completely valid but confusing function like this:

func x239(jke: String) {
    
}

Notice that the function name (x239) and parameter name (jke) provides no clue what they do. Although this code is perfectly valid, it’s confusing so it’s always best to choose descriptive function names and parameter names such as:

func printGreeting(name: String) {
    
}

This function name (printGreeting) and parameter name (name) is much clearer as to the functions purpose, which is to take a name and print a greeting. Of course, this function could actually calculate a differential equation so it’s generally best to choose descriptive function and parameter names that actually describe the purpose of the function.

To call this function, you could use code like this:

func printGreeting(name: String) {
    print ("Hello there, \(name)")
}

printGreeting (name: "Sam")

The function call uses the printGreeting name and identifies the name (“Sam”). This is perfectly fine but in Swift, you have the option to use external parameter names. This means you can have two parameter names, an external and an internal parameter name.

The internal parameter name is what the function actually uses while the external parameter name is what you use to call the function. So to make the function call read more like an actual sentence, you could use an external parameter name like this:

func printGreeting(for name: String) {
    print ("Hello there, \(name)")
}

Notice that the function uses “name” as a variable for the actual code, but when you’re calling the function, you use the external parameter name like this:

printGreeting (for: "Sam")

Now the function call reads like a complete sentence such as “Print greeting for Sam.”

You may not want to do this for your own function declarations and calls, but you’ll find that many Swift API calls use external parameter names specifically to make function calls seem more like a sentence, typically using external parameter names of “in,”, “for”, and “with”.

External parameter names simply help make code more readable although at the expense of also making function declarations more cumbersome to write. You can choose to use external parameter names or not, but whether you use them or ignore them, you’ll at least better understand why so many of Apple’s API functions look the way they do using external parameter names.

Posted in Algorithms, iOS, macOS

January 28th, 2017 by admin

When you create a macOS Cocoa Application project, you project starts out with a Window Controller and a View Controller.

The Window Controller defines the actual window that appears on the screen but the View Controller defines the contents that appears inside the Window Controller. You need to place user interface items like buttons and text fields on the View Controller so when your program runs, these user interface items appear on the View Controller, which appears inside the Window Controller.

A View Controller represents a simple window, but Xcode offers several other types of view controllers such as a Page Controller, a Split View Controller, and a Tab View Controller. If you want any of these other types of controllers to appear inside the Window Controller, you need to follow two steps:

  • Delete the currently existing View Controller
  • Add the new controller you want to put in its place such as a Tab View Controller or Page Controller

To delete the existing View Controller, you need to delete both the View Controller in the storyboard and the ViewController.swift file. To delete the ViewController.swift file in the Navigator pane, just right-click over it and when a popup menu appears, choose Delete.

To delete the View Controller from the storyboard, select the View Controller by clicking the Show Document Outline icon and then clicking on View Controller Scene in the Document Outline. Then press Backspace or choose Edit > Delete.

Initially the contents of the Window Controller displayed View Controller but now it should display No Content View Controller.

Now drag another controller from the Object Library window to the storyboard such as Page Controller or Vertical Split Controller. This will place a new controller on the storyboard but now you’ll need to connect this newly added controller to appear inside the Window Controller.

Click on the blue icon that appears in the top, middle of the Window Controller. Hold down the Control key and Control-drag over the new controller you just added.

Release the Control key and the left mouse/trackpad button. A popup menu appears.

Choose window content. Your newly added controller now displays a connecting arrow to show that it appears inside the existing Window Controller.

Posted in macOS, User Interface, Xcode

January 23rd, 2017 by admin

When working with storyboards in a macOS project, you may want to change the background color of a scene (view). The simplest way to do that is to use this command:

self.view.layer?.backgroundColor = NSColor.blue.cgColor

This simply assigns the color blue (or whatever value you want to insert there such as red or yellow) to the background of the view layer. Of course, writing specific color values into code isn’t very efficient because if you want to change the color, you have to rewrite the code for a new color.

A far better solution is to change the color using code and the simplest way to do that is to assign the backgroundColor of a view to a variable that represents a different color. One way to do this is to use the Color Panel (see this blog post covering the Color Panel).

So if you create a simple macOS project that uses storyboards, place a push button on the view controller and create an IBAction method with a name such as changeBKColor. Declare a color panel underneath the class ViewController line like this:

let colorPanel = NSColorWell()

Now inside your IBAction method, add code like this:

    @IBAction func changeBKColor(_ sender: NSButton) {
        colorPanel.activate(true)
        colorPanel.action = #selector(changeColor)
    }

You’ll need to create a changeColor function like this:

    override func changeColor(_ sender: Any?) {
        self.view.layer?.backgroundColor =  colorPanel.color.cgColor 
    }

If you run this program, a window will appear with a push button. Clicking the push button will run the IBAction method changeBKColor, which displays a color panel. Choosing a color from this color panel then changes the background of the view. The complete code in the ViewController.swift file should look like this:

import Cocoa

class ViewController: NSViewController {

    let colorPanel = NSColorWell()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    @IBAction func changeBKColor(_ sender: NSButton) {
        colorPanel.activate(true)
        colorPanel.action = #selector(changeColor)
    }

    override func changeColor(_ sender: Any?) {
        self.view.layer?.backgroundColor =  colorPanel.color.cgColor 
    }

}

Posted in Algorithms, macOS

HTML Snippets Powered By : XYZScripts.com