User Tools

Site Tools


wiki:software:code:swift:start

Swift

Swift is Apple's answer to Microsoft's .NET (C# specifically). It's a monstrosity of a programming language that takes its cues from Objective-C, which itself implements standards and paradigms that will seem pretty foreign to anyone who isn't already fluent in developing Mac applications.

To date (September 2022) I have written exactly one Swift application. Whether or not I work on any additional projects remains to be seen. I still haven't found a satisfactory screenshot application for 10.14, so that may be on the table. Eventually.

In the meantime, here's a few tips for making your life easier.

Stripping HFS+ extended file attributes from project files

When you're ready to release your project as a compiled, signed binary that others can run, you have to Archive it in Xcode. If you've imported any media files, like images and videos into your project, you're likely going to run into a super weird, overly verbose error:

resource fork, Finder information, or similar detritus not allowed

Don't bother searching online for this error; the solutions I found didn't work as described. You do need to use xattr, which is a command-line utility included with MacOS for working with extended file attributes, but you need to run this on your project, rather than your package.

Navigate to your main project directory in Terminal and type the following:

$ xattr -cr .

This will strip attributes from every folder and file in the current directory. You can verify with:

$ xattr -lr .

The meaning of !, ? and ??

Swift is unable to handle null (nil)1) values on its own. Instead, you have to accommodate any scenario in which a value might return null. This is handled through “safe” and “unsafe” “variable unwrapping”, along with “nil coalescing”. Fortunately, Xcode is good about flagging these operators when they're missing from your code.

Let's look at something simple - reading an element from a dictionary (an unordered list of key-value pairs).

let arrStrings:[Int:String] = [
    1 : "Ein",
    2 : "Zwei",
    3 : "Drei"
]
 
print(arrStrings[0])

This code shows a warning in Xcode. If you choose to force-unwrap with !, your application will crash when it tries to find a key that doesn't exist in arrStrings. The safe way to handle potential null values is with a default value, using the nil coalescing operator - ??.

let arrStrings:[Int:String] = [
    1 : "Ein",
    2 : "Zwei",
    3 : "Drei"
]
 
print(arrStrings[0] ?? "Nein!")

?? is equivalent to if (val == null) { … }.

What about when you're accessing optional properties of an object - that is, properties which may not be set on your object? That's where safe unwrapping comes into play.

statusBarItem?.button?.image = NSImage(named: imgName)

This line references an object which may or may not have a value (because nothing is assigned when it's instantiated), and then an optional property of that object.

? is equivalent to if (val != null) { … } else { //do nothing }.

Using the right types

Make sure to go through Apple's documentation while you're working on your project - you might need string or number methods that are unavailable to Swift types. I ran into this with both strings and doubles. You need to be sure you can do what you want to do with a given type - don't assume functionality.

I really don't know why Apple went this route. It makes no sense to me that an arithmetic operator - modulo, or % - doesn't work with all number types - integers, longs, floats and doubles. I don't know why I can't convert a String to a numeric value, but I can convert an NSString.

1)
Note: Apple uses nil for no other reason than to “be different”. I use null because that's what the word means, and it's what everyone except Apple uses.