Getting Your Feet Wet with Swift: Variables, Constants, and Loops
- Building Blocks of Swift
- Merging Variables into a String
- Optionals: A Gift to Unwrap
- Tuples
- Number Types
- From Objective-C to Swift
- Summary
Swift is a new programming language created by Apple, with the intention of making development of software for Apple products significantly easier. If you have experience in C and Objective-C, you should find Swift to be a walk in the park. All the classes and types that are available to you in C and Objective-C are ported over and available in their exact incarnations in Swift.
If, however, you come from a Ruby or Python background, you will find Swift’s syntax to be right up your alley. Swift borrows and iterates on many ideas from Python and Ruby.
If you come from the JavaScript world, you will be pleased to know that Swift also doesn’t ask you to declare types, as old strict Java does. You will also be pleased to know that Swift has its own version of indexOf and many other familiar JavaScript functions. If they aren’t the exact replicas of said functions, they will at least be familiar.
If you come from the Java world, you will be happy to know that even though Swift does not force you to declare types, you still can and Swift most certainly enforces those types, very strictly.
These are all just basic syntax comparisons; the real magic evolves from Swift’s chameleon-like capability to be written in any way that makes you the programmer comfortable. If you want to write the tersest one-liner that does everything you ever needed in one fell swoop, Swift has you covered. If you want to write Haskell-like functional programming, Swift can do that, too. If you want to write beautiful object-oriented programming with classic design patterns, Swift will do that as well.
In the future (or now, depending on when you are reading this), Swift will be open source so that you can officially (theoretically) write Swift on Linux or Windows. Someone may even create a web framework like Ruby on Rails in Swift.
This chapter covers the basic building blocks of Swift. It starts with variables and constants. With this knowledge, you will be able to store whatever you’d like in memory. Swift has a special feature called optionals, which allows you to check for nil values in a smoother way than in other programming languages. As I briefly mentioned before, Swift has strong type inference; this allows you to have strict typing without needing to declare a type. This chapter also goes over how Swift handles loops and if/else statements.
Building Blocks of Swift
Swift allows you to use variables and constants by associating a name with a value of some type. For example, if you want to store the string "Hi" in a variable named greeting, you can use a variable or a constant. You create a variable by using the var keyword. This establishes an associated value that can be changed during the execution of the program. In other words, it creates a mutable storage. If you do not want mutable storage, you can use a constant. For example, you might record the number of login retries a user is allowed to have before being refused access to the site. In such a case, you would want to use a constant, as shown in this example:
var hiThere = "Hi there" hiThere = "Hi there again" let permanentGreeting = "Hello fine sir" permanentGreeting = "Good morning sir"
Notice that you don’t use a semicolon as you would in many other languages. Semicolons are not mandatory, unless you want to combine many statements together on the same line. In Swift you would not put a semicolon on the end of the line, even though Swift will not complain. Here is an example that shows you when you would use the semicolon in Swift when multiple lines are combined into one:
let numberOfRetries = 5; var currentRetries = 0
Also unique to Swift, you can use almost any Unicode character to name your variables and constants. Developers can name resources using Hebrew, Simplified Chinese, and even special Unicode characters, such as full-color koala emoji.
When declaring multiple variables, you can omit the var keyword. Here is an example:
var yes = 0, no = 0
Computed Properties (Getters and Setters)
In Swift you can also declare variables as computed properties. You would use this when you want to figure out the value of the variable at runtime. Here is an example of a getter, where the value of the score is determined by how much time is left. In this example we are creating a read-only computed property.
var timeLeft = 30 var score:Int { get{ return timeLeft * 25 } } print(score)
In this example we can reference (or read) score anywhere because it is in the global scope. What is really interesting is that if we try to set the score, it will give us an error because we have created a read-only property. If we want to be able to set this property, we need to create a setter. You cannot create a setter without a getter. Aside from the fact that it would not make sense, it also just will not work. Let’s create a setter to go along with our getter. It does not make sense for a setter to set the computed property directly because the value of the property is computed at runtime. Therefore, you use a setter when you want to set other values as a result of the setter being set. Also, setters work well in some sort of organizational unit, which we haven’t covered yet, but it’s worth diving into briefly. Here is a full Swift example, which includes many elements we have not covered yet.
import UIKit struct Book { var size = CGSize() var numberOfPages = 100; var price:Float { get{ return Float(CGFloat(numberOfPages) * (size.width * size.height)) } set(newPrice){ numberOfPages = Int(price / Float(size.width * size.height)) } } } var book = Book(size: CGSize(width: 0.5, height: 0.5), numberOfPages: 400) print(book.price) book.price = 400 print(book.numberOfPages)
In this example we create a book Struct, which is a way to organize code so that it is reusable. I would not expect you to understand all of this example, but if you have ever coded in any other languages, you will notice that there is a lot of type casting going on here. Type casting is a something you do all the time in Objective-C and most other languages. We will cover all aspects of this code in this book, but you should know that we created a setter, which sets the number of pages in the book relative to the new price.
Using Comments
You indicate comments in Swift by using a double forward slash, exactly as in Objective-C. Here’s an example:
// This is a comment about the number of retries let numberOfRetries = 5 // We can also put a comment on the end of a line.
If you want to create comments that span multiple lines, you can use this /* */ style of comments, which also works well for documentation.
/* Comments can span multiple lines */
Inference
Swift uses inference to figure out what types you are trying to use. Because of this, you do not need to declare a type when creating variables and constants. However, if you want to declare a type you may do so, and in certain situations, it is absolutely necessary. When declaring a variable, the rule of thumb is that Swift needs to know what type it is. If Swift cannot figure out the type, you need to be more explicit. The following is a valid statement:
var currentRetries = 0
Notice that Swift has to figure out what type of number this is. currentRetries may be one of the many types of numbers that Swift offers (Swift will infer this as an Int in case you are wondering, but more on that later). You could also use this:
var currentRetries:Int = 0
In this case, you explicitly set the type to Int by using the colon after the variable name to declare a type. Although this is legit, it is unnecessary because Swift already knows that 0 is an Int. Swift can and will infer a type on a variable that has an initial value.
When do you need to declare the type of a variable or constant? You need to declare the type of a variable or constant if you do not know what the initial value will be. For example:
var currentRetries:Int
In this case, you must declare Int because without it, Swift cannot tell what type this variable will be. This is called type safety. If Swift expects a string, you must pass Swift a string. You cannot pass an Int when a String is expected. This style of coding is a great time-saver. You will do a lot less typing with your fingers and a lot more thinking with your brain. Every default value you give a variable without a type will be given a type. Let’s talk about numbers first.
For number types, Swift gives us the following:
Int is available in 8, 16, 32, and 64 bits, but you will most likely stay with just Int. It’s probably large enough for your needs. Here’s what you need to know about Int:
Int on 32-bit platforms is Int32.
Int on 64-bit platforms is Int64.
That is, when you declare a variable as Int, Swift will do the work of changing that to Int32 or Int64. You don’t need to do anything on your end.
Int can be both positive and negative in value.
Int will be the default type when you declare a variable with a number and no decimals:
var someInt = 3 // this will be an Int
UInt is provided as an unsigned integer. An unsigned number must be positive, whereas a signed number (an Int) can be negative. For consistency, Apple recommends that you generally use Int even when you know that a value will never be negative.
Double denotes 64-bit floating-point numbers. Double has a higher precision than float, with at least 15 decimal digits. Double will be the chosen type when you declare a variable that has decimals in it:
var someDouble = 3.14 // this will be a double
Combining any integer with any floating-point number results in a Double:
3 + 3.14 // 6.14 works and will be a double var three = 3 var threePointOne = 3.1 three + threePointOne //Error because you can't mix types
- Float denotes 32-bit floating-point numbers. Float can have a precision as small as 6. Whether you choose Float or Double is completely up to you and your situation. Swift will choose Double when no type is declared.
Along with Decimal numbers, you can use Binary, Octal, and Hexadecimal numbers:
- Decimal is the default for all numbers, so no prefix is needed.
- Create a Binary number by adding a 0b prefix.
- Octal uses a 0o prefix.
- Hexadecimal uses a 0x prefix.
You can check the type of the object by using the is keyword. The is keyword will return a Boolean. In this example we use the Any class to denote that pi can be anything at all until we type it as a Float:
var pi:Any? pi = 3.141 pi is Double //true pi is Float //false
Notice that you declare this type as Any? in the preceding example. The question mark denotes an optional, which allows us to not set an initial value without causing an error. The Any type can be any type (exactly what it says). Objective-C is not as strict as Swift, and you need to be able to intermingle the two languages. For this purpose, Any and AnyObject were created, which allows you to put any type in an object. Think about arrays in Objective-C, which can mix different types together; for that purpose you need to give Swift the ability to have arrays of different types. You’ll learn more about this later in the chapter.
Swift is the only programming language (that I know of) that lets you put underscores in numbers to make them more legible. Xcode ignores the underscores when it evaluates your code. You might find using underscores especially useful with big numbers when you want to denote a thousand-comma separator, as in this case:
var twoMil = 2_000_000
Before you can add two numbers together, they must be made into the same type. For example, the following will not work:
var someNumA:UInt8 = 8 var someNumB:Int8 = 9 someNumA + someNumB //Int8 is not convertible to UInt8
The reason this does not work is that someNumA is a UInt8 and someNumB is an Int8. Swift is very strict about the combination of things.
To make this work, you must convert one of the types so that the two types are the same. To do this, use the initializer of the type. For example, you can use the initializer UInt8, which can convert someNumB to a UInt8 for you:
someNumA + UInt8(someNumB)
Swift is strict and makes sure that you convert types before you can combine them.
We had to do a lot of conversions of types in a previous example.