Menu
In the first part of the iOS to Mac development series here on The Syndicate, we discussed the tools, macOS app anatomy, languages, and SDK differences between iOS and macOS. Reading through the documentation, you’ve probably noticed a lot of differences in the way macOS handles interfaces and view controllers, especially since macOS apps can handle multiple windows displayed at the same time.
AppKit contains all the objects you need to implement the user interface for a macOS app—windows, panels, buttons, menus, scrollers, and text fields—and it handles all the details for you as it efficiently draws on the screen, communicates with hardware devices and screen buffers, clears areas of the screen before drawing, and clips views. Hacking with macOS teaches you Swift and macOS frameworks through real-world AppKit and SwiftUI projects. The book includes the same comprehensive Swift introduction as Hacking with Swift, but is also packed with hints and tips that help you transfer your existing iOS skills to macOS painlessly. AppKit contains all the objects you need to implement the user interface for a macOS app—windows, panels, buttons, menus, scrollers, and text fields—and it handles all the details for you as it efficiently draws on the screen, communicates with hardware devices and screen buffers, clears areas of the screen before drawing, and clips views. Swift Programming Exercises, Practice, Solution - w3resource (w3resource.com) Intermediate Swift 3 raywenderlich.com (raywenderlich.com) Swift Fundamentals (pluralsight.com.) AppCoda - Learn Swift, iOS, iPadOS, macOS App Development (appcoda.com) iOS 11 & Swift 4: From Beginner to Paid Professional™ (udemy.com.).
In this final conclusion of the article, you will learn about view controllers on macOS and how they work with windows and views.
About Reminderz
There’s no better way to learn about creating a macOS app than to actually create an app, so in this article, we’ll build out an app called “Reminderz” (it has a “Z” in the name, so it’s totally investor-worthy and totally hip… that’s still cool, right? Good, then we’ll secure the .io domain name).
Reminderz is, well, a todo list app with the following capabilities:
Project SetupCreating the Project
Start by opening Xcode and following these steps:
Configuring the AppDelegate
To begin, we want to configure the AppDelegate for the type of app we’re building. For this particular app, we will use a single-window construction, and one of the common features of apps with a single window in macOS Lion and later is to have the app close whenever the user closes the last window.
To do this, open the AppDelegate.swift file and add the following method:
Returning true in this method causes the app to automatically close when the user closes the last window (or in our case, our only window), which is exactly what we want for this app.
Creating the Data Manager
In order to save, load, and schedule notifications for reminders stored in the Reminderz app, we will first create a data manager. This manager will handle all of these tasks.
First, however, we need to create our base reminder class that the app uses. This object is called “TodoItem” and it has two properties: todoName (String) and todoDueDate (Date).
Create a new Swift file and add the following class definition:
In the
TodoItem code above, the class conforms to NSCoding, since we will be storing multiple TodoItem objects in an array, then serializing that array to disk using UserDefaults. We implement a custom initializer to more quickly instantiate an object. Lastly, the class overrides the isEqual function to check and see if a passed in TodoItem object is the same as the current one. This will be used with our array handling later on.
Now on to the DataManager class, which will handle loading, storing, and removing TodoItem objects for the app. Create a new Swift file called
DataManager.swift , and then copy the following code into the class.
Let’s look at each one of the class methods:
Creating the View ControllerFirst, a little about NSViewController…
NSViewController is a similar to UIViewController on iOS in that it has various methods that gets called throughout the view lifecycle:
Through these view controller events, you can setup and teardown a view controller on macOS just like on iOS. These lifecycle methods are available beginning in macOS 10.10 (Yosemite).
![]()
In addition, NSViewController has a view that contains user interface elements added through either a XIB or a Storyboard scene (with macOS 10.10 and higher, Storyboards are now preferred).
Now that you know a little more about the lifecycle methods of NSViewController, let’s build out the main interface controller in Swift. When you created a Cocoa Application project, a single view controller was automatically created for you called “ViewController.swift.” Open this file, and edit it to look like the ViewController code below:
Let’s cover each section in-depth to get a feel for what this controller is doing:
Laying Out the Storyboard Scene
Now that the view controller code has been completed, it’s time to lay out the interface in a Storyboard. To begin, open the Main.storyboard file.
You should see something that looks like the screenshot below.
This is the standard layout for a new Cocoa Application template. To the top is the Main Menu scene that shows the menu bar items that will appear in the top left of the screen when the app is running and the frontmost app.
To the left, there is an NSWindowController instance with an NSWindow embedded inside. The windowContent property of NSWindowController is set to the NSViewController on the right through a segue-style link.
The NSWindow instance defines window height, width, and window title. Select the Window in the scene, and open the Attributes Inspector. Set the “Title” property to “My Reminderz.” Next, open the Size Inspector and set the Minimum Content Size and Maximum Content Size to 480w x 270h as the window we’ll create will not be resizable.
Next, let’s move onto the NSViewController instance, which has the class set to ViewController in the project. Begin creating the UI by first dragging out an NSTableView from the Object Library. Apply the following AutoLayout constraints just as you would to a view in iOS:
https://treefaith.weebly.com/foxpro-app-for-mac.html. The view will now look like this:
Next, double-click the table header view for the first column and rename it “Item,” then, do the same for the second column renaming it “Due Date.”Next, drag out the following objects:
When you are done, add AutoLayout constraints to the newly added objects to make it look like the following finished product:
Now that all of the UI elements are in place, the IBOutlets to the table view, name text field, date picker, and wire the IBAction of the todo. You can do this by Control + dragging from the ViewController object in the Storyboard scene to all of the objects to assign IBOutlets, and from the button to the ViewController object to assign the IBAction, just like with iOS.
If you run the app at this point, you may notice that the app runs, and you’re able to create a new todo; however, nothing appears in the table view. This is due to the fact that the identifiers for the cells hasn’t yet been set.
To set the identifier for these cells, select the “Table Cell View” under the Item column in the scene outline view, then open the Identity Inspector with this view selected, ensuring “nameCell” is added. Repeat this for the Due Date Table Cell View, ensuring the identifier is set to “dateCell.”
Now when you build and run the app, you’ll notice the items appear now that the cells are being registered and populated appropriately in the table view.
After setting the identifier for the individual cells, click the column object called “Item” and “Due Date,” adding the column identifier of “itemColumn” and “dueDateColumn”, respectively.
Adding Keyboard Shortcuts for Deleting Items from Table ViewMacos App In Swift Now
The Mac relies a lot on keyboard shortcuts, because instead of iOS where input is mainly touch-driven, the Mac is completely driven by keyboard and cursor-based input.
NSResponder (similar to UIResponder on iOS) provides method callbacks such as keyDown and deleteBackward. Whenever there’s a key down event, this method lets the system interpret the key event, which will in turn march up the responder chain, looking for a view that can handle the key event. In the event that the delete key is pressed, then the deleteBackward method will be executed. In this method, we request the selectedRow, an integer value, from the tableView. We check to see if this value is -1, which NSTableView returns when no row is selected. Finally, we call the removeTodoItem method on the DataManager instance, passing in the todoItem to be removed.
![]()
Below is the code that needs to be added to ViewController.swift to add keyboard shortcuts to the table view:
Working with the Responder Chain
As we mentioned above, keyboard shortcuts are very important, and users being able to navigate through your app using only keyboard shortcuts is vital to some users. The way this is accomplished on macOS is through the tab key — as the user presses tab, the application automatically moves on to the next responder.
In macOS, you can chain up responders in Storyboards, allowing the user to move from one view to the next using the tab key.
We’ll add this to the app by opening the ViewController scene in the Storyboard and selecting the Todo Name Field in the outline view, then open the Connections Inspector. Note the
nextKeyView outlet — drag from the outlet to the next NSView subclass in the scene that should be moved to whenever the user tabs from the current view.
For this app, add connections for the following views:
Now, whenever you build and run the app and tab through the interface, the Todo Name Field will be the first responder (as this is set in code when the View Controller first loads), then you will be able to tab in order from the date picker, to the add button, to the table view, and then back to the todo name field.
Adding Local Notification Reminders
Local notifications are a feature of this app: Whenever you add a todo, you’ll want to have a notification scheduled so that even if the app is closed, macOS will remind you about the todo item. Notifications have long been a feature of iOS, and macOS includes the same functionality for scheduling both remote and local notifications. In this example, we’ll use the local notification model to schedule notifications for the user since that implementation makes the most sense.
Add the following code (replacing the existing
addTodoItem and removeTodoItem code) in the DataManger.swift file:
In the createNotification method, a new NSUserNotification (similar to UILocalNotification) is created with a title, subtitle, and deliveryDate that the user selected, then is registered the NSUserNotificationCenter.
The removeNotification method searches through the scheduled notifications in NSUserNotificationCenter, finds the matching scheduled notification, then removes it so the user will no longer be notified for deleted todo items.
Building and Running
Once all of the code is in place, build and run the app. You’ll notice that we’ve now fulfilled all of the requirements set out originally in the first part of this post. The app can create todos, which in turn schedules local notifications. You can also delete existing to dos and remove their scheduled local notifications.
Congratulations on building your first Mac app. There are many things that are still to be learned to build more sophisticated macOS apps, but this small project will hopefully help you to start looking at the Mac with more open eyes.
Get the Sample Code
If you don’t want to follow along with the example above, then check out the sample code for the app built in this post.
Anyone familiar with my ramblings will be aware that I mostly develop in C# using a mixture of Xamarin and .NET Core depending on what I’m building. Earlier this year I took the decision that I’d be serious about learning Swift and got started with building a simple utility app for macOS to help me find training images for some machine learning.
The app has mostly just sat on Github with little love since I originally published it, so this week I dusted it off (I actually just cloned it again from Github but I like the metaphor) and started implementing a few of the features that didn’t make it to the first release. The most obvious is file tagging, which makes it possible to add file system tags to exported images, for easier discovery of exported images.
I shared a gif of the new build with a colleague, and he loved it so much that he wanted a copy. Now I could have easily have behaved like an animal and built a version on my development machine and sent over the results, but instead, I opted to listen to the sane part of my brain that was calling for me to set up a CI/CD pipeline.
Enter Microsoft’s App Center
If you’re not familiar with App Center then you’re in for a treat! App Center provides a one-stop-shop for services that app developers will likely need. This includes building, testing, distribution, analytics and crash reporting to name a few. Today I’m going to focus on the build aspect, but I’ll cover other features in upcoming posts.
Microsoft has been working hard on adding new features to App Center, and one of those new features in the preview is the ability to build Swift macOS apps. The setup process only requires a few clicks, and we’re up and running. Below a gif of the process recorded in real-time which shows how quickly I managed to get a build setup and running.
Macos ProgrammingApp Center Build Setup
To get started we have to create a new app within App Center and specify a name OS and platform as a minimum. In my case, I only really need to worry about selecting macOS as App Center currently only supports Objective-C and Swift as languages for macOS app development.
Setting up the build pipeline
Once we’ve clicked “Add New App”, we’ll be presented with a screen encouraging us to integrate App Center SDKs into your app. I’ll cover the advantages of this in another post as it’s not needed to use App Center. Did I mention that every feature in App Center is optional? In the post, we’re only going to use the build and distribute functionality and ignore everything else.
Build Configuration
As mentioned earlier in the post, the code is hosted on Github which is integrated with App Center. This allows me to connect App Center to the repository and anytime I push to a branch I can have App Center automatically trigger a build.
Once I’ve selected Github I’m presented with a list of all my repositories for me to select which one I wish to link to my App Center App.
In this example, the repository only has one branch so I’ll select that puppy and move onto configuration.
Build Configuration
We want to do a few things with the build configuration. Number one, it has to sign the build for distribution using my Apple Certificates and secondly I want to increment the version number of the app automatically.
Signing builds
In order to sign builds for distribution, we’ll need to upload a copy of our .p12 file and a valid provisioning profile.
Incrementing build numbers
App Center has native understanding of our projects info.plist file (thanks to the work they did on supporting iOS) so incrementing the build number only requires a few button clicks to configure.
Distribution
We’re almost finished configuring the build process but we’ve one last step to configure and that’s distribution!
By default, the distribution list is a little lonely as it’ll just be you, but as you find people excited to try your apps you can add them to lists and control what versions of the app they get. For example, you might want your VIPs to get GM access and staff to have access to betas.
Adding distribution groupsSwift For Apple
To setup my VIPs distribution list I head over to the “distribution” beacon on the left hand menu and click “Add Group”.
Right now I’ve only one VIP and that’s my colleague Dean but this is enough to demonstrate the functionality. Best mac to do apple. It’s worth noting that I need to pop back to the build configuration to update the distribution to VIPs if I want Dean to get a copy of the builds triggered from Master.
Distribution emailSwift Mac
Best desktop applications 2019. And with only a few clicks, my users will now get a nice email with a link to install the latest and greatest builds of my app!
ConclusionSwift Playground Mac Os
App Center is a powerful tool for app developers to streamline their development processes from building, distribution to monitoring after release. I hope this post has helped you understand how easy it can be to set up a CI/CD pipeline for macOS apps developed with Swift 4.0. If you’ve any questions or feedback then please don’t hesitate to reach out.
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |