The places where Swift isn’t so intuitive.
It usually is. Intuitive, that is. Usually Swift is intuitive, with optionals and drag-and-drop kind of building of GUI elements.
But other times it isn’t intuitive at all. It redefines keywords from popular languages like C++
and Python
, and the division between Storyboards and code can be incredibly confusing.
Here are 5 places that confused me when I started out. We will use Swift 5 in Xcode 11.5 using Storyboards —note that SwiftUI redefines the wheel again, but maybe for the better.
Public, internal, fileprivate and private, but no protected
Never mind what C++
has already established about the meanings of classes and structs (structs are classes with no private members). Just forget everything that already exists and learn it again — the Swift
way.
Instead, in Swift
, the key difference is: structs are passed by value, while classes are passed by reference.
Let’s take a look at an example using structs
:
This fails to compile in the method that modifies the struct, because it is passed by value, and therefore cannot be modified:
Changing struct
to class
, on the other hand, works just fine:
Let’s start by creating two view controllers: MainViewController
and SetDataViewController
.
MainViewController
has a simple message text field and a button.SetDataViewController
has a text field and a button.Let’s hook it up such that pressing the button goes to the SetDataViewController
. Click and drag from the button to the view controller to create a segue.
We can now name the segue:
And then add additional logic in the navigation section in MainViewController
:
That works for the forward segue —but what about an unwind segue to go back?
To unwind, you start in the code. In the destination view controller MainViewController
, add a returned
method:
Then in the storyboard, hook up the unwind segue in the SetDataViewController
. Click and drag from the button to the Exit
at the top:
and select the returned
method:
You can find the segue in the left hand side, and give it a name like returnedSegue
as before:
That’s it!
Very frequently you will want to call a method of one view controller from another view controller. This is best done using protocols and delegates. If you are used to the idea of abstract base classes in C++
or Python
, protocols
are like an interface that a class promises to implement.
Let’s use the example from the last section.
MainProtocol
, which declares a method handleData
. It inherites from AnyObject
such that only classes can inherit from it.MainViewController
inherit from MainProtocol
, and add an implementation for handleData
.optional
weak
delegate
in SetDataViewController
, and call it in the navigation code for the returnedSegue
. Note that it must be weak to break the strong reference cycle (if you don’t use weak
, the reference counts of the view controllers do not reach zero, so they don’t get deallocated).delegate
in the MainViewController
navigation:This is the most general and powerful method for calling methods in different view controllers and passing data back and forth. The final MainViewController
looks like this:
By default, you can inherit from any class you wish. The open
keyword makes this explicit (but redundant):
The console will show Goodbye
. We can change open
to final
to prevent inheritance:
This will prevent inheritance:
You can also apply it to a method rather than a whole class:
This allows inheritance but prevents override
of the say
method:
Using open
and final
you can control closely how your classes can be reused.
InPython
you may be used to import
statements, or include
in C++
to include headers defining different methods.
Well it turns out in Swift
, by default everything is just internal
p̵u̵b̵l̵i̵c̵, meaning every class/method you define is available from any other file in your project (although not outside a module). Obviously, this is almost never what you want!
Even if you don’t care about it explicitly, note that leaving everything as internal increases compilation time. So it’s worthwhile using the other access levels appropriately: public
, internal
, fileprivate
, and private
.
public
o̵r̵ ̵n̵o̵t̵ ̵g̵i̵v̵i̵n̵g̵ ̵a̵n̵y̵ ̵a̵c̵c̵e̵s̵s̵ ̵l̵e̵v̵e̵l means the method/class is available from anywhere in the project.internal
or not giving any access level means things can only be used from within the same module.fileprivate
means that things can only be used from within the same file.private
means you can only access it from within the same class you defined it in.Note that private
also has the usual meaning from C++
for classes, in that subclasses cannot access private
attributes.
If you are wondering what the equivalent of the protected
keyword from C++
is (protected
attributes can only be accessed from an inherited class): there is none. It’s just public
and private
because…. Yep.
Yes, Swift has lots of nice features and makes iOS programming like a breeze. Yes, it feels like Swift reinvented the wheel sometimes, and redefines keywords you already know. Yes, simple things can be so unintuitive between code and storyboards.
And yes, I wish I had known these things sooner.
Oliver K. Ernst
August 1, 2020