Presentation on Swift 1.0 to give those coming from other languages a brief overview of the language. Presented first at Reasons to Be Creative, Brighton. 2015
15. If…else
var num = 10
if num < 20
{
println(“less than 20")
}
else
{
println("not less than 20")
}
16. Switch…Case
var value = 10
switch value
{
case 10:
println("Yay! just right")
case 20:
println("a bit too high")
default:
println("Nothing to see here")
}
17. Switch…Case
var value = 6
switch value
{
case 1...9:
println("Too low")
case 10:
println("Yay! just right")
case 20:
println("a bit too high")
default:
println("Nothing to see here")
}
44. Closures
var namesArray = ["Mike", "Darren", "Dennis", "Jason", "Macca"];
let myFriends = sorted(namesArray,
{ (s1:String, s2:String) -> Bool in
return s1 < s2;
})
45. in…out
var month = 9
var year = 2015
func swapTwoInts(inout a: Int, inout b: Int)
{
let tempA = a
a = b
b = tempA
}
swapTwoInts(&month, &year)
// month = 2015, year = 9
49. Classes
class Person
{
var firstName: String;
var lastName: String;
init(fName:String, lName:String)
{
firstName = fName;
lastName = lName;
}
}
let myPerson = Person(fName:"Mike", lName:"Jones")
50. Classes
class Person
{
var firstName: String;
var lastName: String;
init(fName:String="John", lName:String="Smith")
{
firstName = fName;
lastName = lName;
}
}
let myPerson = Person(fName:"Mike", lName:”Jones”)
// fName = "Mike", lName = "Jones"
let myDefaultPerson = Person()
// fName = "John", lName = "Smith"
51. Classes
class Person
{
var firstName: String;
var lastName: String;
init(fName:String, lName:String)
{
firstName = fName;
lastName = lName;
}
convenience init()
{
self.init(fName: "John", lName: "Smith");
}
}
let myPerson = Person() // fName = "John", lName = "Smith"
52. Classes
class Person
{
var firstName: String;
var lastName: String;
init(fName:String, lName:String)
{
firstName = fName;
lastName = lName;
}
deinit
{
// Clean up here
}
}
53. Classes
class Person
{
var firstName: String;
var lastName: String;
var fullName:String
{
get
{
return self.firstName + " " + self.lastName
}
}
// …
}
63. Generics
func swapTwoInts(inout a: Int, inout b: Int)
{
let tempA = a
a = b
b = tempA
}
func swapTwoStrings(inout a: String, inout b: String)
{
let tempA = a
a = b
b = tempA
}
func swapTwoDoubles(inout a: Double, inout b: Double)
{
let tempA = a
a = b
b = tempA
}
64. Generics
var month = 9
var year = 2015
var greeting = "Hello Reasons"
var response = "Pleased to meet you :)"
func swapTwoValues<T>(inout a: T, inout b: T)
{
let tempA = a
a = b
b = tempA
}
swapTwoValues(&month, &year)
// month = 2015, year = 9
swapTwoValues(&greeting, &response)
// greeting = "Pleased to meet you :)
// response = "Hello Reasons
Let’s start off with a point of reference that we can use as a starting point
This is a Unicorn - in case there was some confusion. The rest of this presentation is about Swift!
This should look familiar to those ActionScript developers in the audience.
Seriously though let’s just take a look at the anatomy of this line of code:
It declares the property using the VAR keyword, and provides clear indication though TYPE ANNOTATION that it is expecting a STRING as a value.
This is what we would all refer to as an example of a STRONGLY TYPED language
This on the other hand will be familiar to all the JavaScript developers in the house. Note the lack of a TYPE ANNOTATION and a terminating semi-colon.
The type of data this variable can store is INFERRED by the value that is assigned to it. This is what you would usually refer to as a DYNAMIC LANGUAGE as the variable will happily store whatever you provide it with, a STRING one moment, a NUMERIC VALUE the next.
Now this may come as no surprise, but both of the preceding examples were in fact SWIFT. Swift uses TYPE INFERENCE to determine what a variables type is based on the initial value assigned to it.
However, unlike JavaScript it is a STRONGLY TYPED language and through a process referred to as TYPE SAFETY it makes sure during development and compilation that you don’t try and assign a different data type to a previously declared variable. If you do you’ll get an exception!
You can annotate your variables with a specific type at declaration (and include semi-colons if you wish), but they are not required.
One other thing before we move on is the difference between LET and VAR. LET is the CONSTANT keyword, so any value assigned to this type of variable is fixed and cannot be changed at a later time.
As with most languages SWIFT controls execution flow through the use of LOOPS & CONDITIONALS.
However while they operate in a similar fashion to other LANGUAGES you may be familiar with, except that curly braces are mandatory while parentheses aren’t. Also be aware that unlike a lot of WEB LANGUAGES, you can create infinite loops.
Loops available are FOR, FOR…IN, WHILE & DO…WHILE
Here we have the FOR loops. I’m not going to deep dive in to these. They are solely here to provide a point of reference where SWIFT offers differing implementations. For example CURLY BRACES are MANDATORY. PARENTHESES are not.
This is the equivalent of the previous FOR loop. In this case it is using the HALF RANGE (..<) to loop through the values 0-9. If you wanted the loop to include the value 10, use a full RANGE (…)
The more modern FOR…IN loop. This is the best practice approach advocated by Apple for iterating over ARRAYS etc.
The WHILE loop. Make sure to include the incrementation variable otherwise you can easily create an infinite loop!
Classic DO…WHILE. Again just to re-enforce, CURLY BRACES are required, PARENTHESES are not
Like LOOPS, CONDITIONALS require CURLY BRACES even if you are doing a single line evaluation.
Conditionals include: IF…ELSE & SWITCH…CASE
Another thing to note is that SWITCH CASE statements do not support FALL THROUGH and you have to supply a ‘CATCH ALL’ should none of the CASE STATEMENTS fulfil the condition. BREAK statements are optional and are inferred - hence the lack of FALL THROUGH
If you do want to ‘emulate’ a FALL THROUGH and you value is an INT, then you can use a RANGE to achieve this as shown above.
Optionals, or SOME & NONE…
This is how most people feel on first encountering OPTIONALS…
Here we have the declaration of an OPTIONAL INT. Note the shorthand (and preferred) way of declaring the optional - Int?. Don’t confuse Int? with Int. Optionals are a separate type of their own that contain the property type you assign.
The second line illustrates the ‘long form’ approach to declaring Optionals - and thus re-enforces that they are their own type.
As the second line type annotation implies, this is an implicitly unwrapped optional. That is on assignment it unwraps the optional and assigns the property value to the variable. Be aware this will error if the type cannot be converted - as shown in the next few slides.
As toInt() is an optional, myInt will have a type of Int? and the value of nil as myString cannot be converted to a number
This time myInt has the value of 3. Remember though this is still an Int? not an Int
This assigns the value of 3 to the variable myInt, but it sets it’s inferred type to Int? not Int as you may assume
Here we get an error as the OPTIONAL object hasn’t been force unwrapped and is still an Int? and not an Int
Here we get an error as the OPTIONAL object hasn’t been force unwrapped
To achieve this we just added an exclamation mark to the end of toInt()
Now the value of myInt is not only 3, but is also an Int not an Int?
Be careful doing this in this manner as you will get an error if you try and force unwrap an OPTIONAL and chain it at the same time - as nil doesn’t have an advancedBy() method - so throws an error.
Here we get an error as the OPTIONAL object has been force unwrapped and it is a nil value
A cleaner approach is to using CONDITIONAL UNWRAPPING of an optional (this slide also demonstrates the concept of chaining).
Here the variable myInt is part of a conditional expression so if the resulting value is nil, the condition is then false and the ELSE is run. If the value isn’t nil, then it is TRUE and the first statement is run - setting the value of myOtherInt in this case.
Note myInt is garbage collected after this condition finishes its execution
By default parameter names do not get displayed when invoking a function. While this can be fine in most instances you may want to display the parameters so you can give another developer an indication of what each value represents.
If you want to make it more explicit what the parameters are that are being called you can prefix them with a hash #. Then when invoking the function you have to include the parameter names
When using CONVENIENCE NAMES for PARAMETERS you still have to use the actual parameter name within your function. Using the convenience name will throw an error.
Tuples are simple objects that allow you to plass back multiple values from a Function / Method. By default they are 0 based
Tuples, like Function parameters, can have name parameters. In which case they can be accessed by the parameter names instead.
Instead of naming the TUPLE parameters you can just declare the names as variables - in this case constants - and do the assignment and initialisation all at once.
If there are any parameters you don’t require place an underscore _ in the position of the item you don’t require and it will not be created or assigned in this manner.
VARIADIC FUNCTIONS allow you to provide a simple parameter signature that allows an arbitrary amount of items of a certain type.
Note the return of the RANGE
Here we can pass a function around and assign it to another variable by declaring the receiving variable as having the same FUNCTION TYPE as the function that is passed to it.
So in this example we declare our variable as taking 2 INT PARAMETERS and returning 1 INT PARAMETER.
This slide is a lay-up showing a function being used as a parameter of the SORTED function - this will be replaced by a CLOSURE in the next slide…
CLOSURES or function literals are common in a lot of languages, but SWIFT has a specific way to declare a CLOSURE as you can see here.
CURLY BRACES, then the parameters and the return type (if required). The all important IN keyword and then the actual closure code.
In this example it just sorts the array alphabetically.
In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let.
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.
Structs are created using the STRUCT keyword and can contain both properties and methods.
Structs are useful when you need to create a complex data transfer object on an ad-hoc basis within your application. Do not confuse these with an OBJECT LITERAL. STRUCTS can be instantiated like CLASSES.
While SWIFT does create an INITIALISER in the background, by default it only calls the SUPER CLASS if there is some form of INHERITANCE.
To fix our class all we need to do is create an EXPLICIT INITIALIZER that assigns values to our properties on INSTANTIATION.
Now we have another problem. In it’s current form a PERSON CLASS always has to have a value for FIRSTNAME & LASTNAME supplied on creation. We can resolve this in a few different ways.
Firstly we could supply defaults for those values. Or…
We can create a CONVENIENCE INITIALISER. These are as the name implies a way to set additional INITIALISERS that allow for increased configuration on INSTANTIATION.
With a CLASS you also have access to a deinitializer - DEINIT. This is when you destroy the object, either manually by setting it to NIL or as part of ARC.
Getters & Setters are computed values not stored values
Inheritance works the same as other languages except when dealing with variables
As JobDescription is a stored value we cannot override it in the Manager subclass. To achieve this though we can create a computed variable of the same name and set the value that way.
Note we have to call back up to the SUPER version of the variable to actually store it.
PROTOCOLS are what a lot of languages refer to an INTERFACES. These are contract files that tell a class what METHODS and / or PROPERTIES they need to implement to fulfil that contract
EXTENSIONS allow you to ADD FUNCTIONALITY to a object that you may not have access to the source code. Think of this like adding properties and methods to a JavaScript object via the PROTOTYPE chain.
Not that they are actual implementations and have ACCESS MODIFIERS where required
GENERICS are the ability to create GENERIC FUNCTIONS & METHODS that allow for greater flexibility within your code without the necessity of REPETITION.
These are a few of the GENERIC TYPES in SWIFT - some we have already seen
Take this contrived example - these 3 functions are pretty much identical. However it would be more efficient if we could do the same thing with just one function. That’s where GENERICS come in.
Not the use of the token identifier <T>. The only requirement is that the type annotation <T> be the same as the parameters that are passed in
This is a big deal as it allows the potential for iOS developers (initially) to build end to end applications solely in SWIFT - similar to the JS -> Node.js approach.