Swift Learnings
Back to square one
By ahchao in Learning Swift
September 11, 2021
I’ve been trying to learn some Swift lately (didn’t really learn/use it like properly properly) and I’m trying to document down some of my takeways or learning points. This is going to be a on-going and confusing document, but from time to time I will try to reorganise this.
struct
and enum
is similar - they are both value type.
enum
carry data too! but no stored properties; functions/computed props are fine.
class
?are reference type.
struct
are stored on the stack, class
es are stored on the heap.
However, Swift has this thing called stack promotion, where class
es can be stored on the stack in the situation allows. So the above point is not always strictly followed. Smart swift!
struct
s are preferred in swift (https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes), while class
es is only when required (e.g. need to be shared by many people or identity related).
struct
s are ‘faster’ compared to class
es since the cost of copying, alloc+dealloc, reference counting, is higher on class
es. Since it is also copy-on-write, (AFAIK) arrays and dictionaries are also copied but on reference level (i.e. still pointing to same data), but once you modify it, it then copies for real. Think of it as lazy/delayed copy, so actual duplication of array/dictionary data only takes effect when it actually happens. We don’t get this COW ‘feature’ for free with our own data types. Source: https://www.hackingwithswift.com/example-code/language/what-is-copy-on-write
Also in some situation, even struct
objects can be allocated to the heap or costs even more than a class
, e.g. a struct
(value type) having vars of class
(reference type) and we have copies of that struct
(causing more retain count on those vars of class
).
When a struct
conforms to a protocol it also has higher allocation costs.
There is no need for ‘new’, everything is as per above. i know this is counter-intuitive to what I learnt in cpp where new
= heap and non-new
= stack. Swift does everything for you based on value/reference type.
Swift has functional aspects and types like in javascript/typescript. The confusing part is that swift is var
(variable) and let
for consts, but in js/ts it’s let
and const
respectively.
Source: https://www.vadimbulavin.com/value-types-and-reference-types-in-swift/
Also some recap:
- Objc/Swift uses ARC, automatic reference counting, which is an ownership system. Basically concept is like smart pointer in C++. Whenever something new reference the referenced object, the retain count of that referenced object is +1, and if they are set to nil, retain count is -1. Same in Objc, it has
weak
andstrong
concept. If retain count is 0, that object is doomed to die. Because of the ownership system the one thing we need to take note of is 2 objects having astrong
reference to each other, causing the system to not know when to delete them since retain count is forever +1… When retain count is 0, anyweak
references are zeroed out (i.e. set tonil
). In Swift, they also introducedunowned
, basically it’s a flavour ofweak
, which I think it’s mainly used if you are sure the object you are referencing will not be zeroed out or app will crash (so it is more tightly coupled?). We should prefer to useweak
when it is not clear if the captured object will outlive our var/closure. - Apparently for weak references, this thing calledSide-Tables
entry is how the retain count are being tracked andweak
reference points to them (and not the actual object in the heap). - It is also cool to know that the destruction of the reference object is not destroyed immediately - they have a life cycle too (live -> deiniting -> deinited -> freed -> dead), and depending on the
weak
/unowned
/strong
references that is left remaining that reference to it, the life cycle stage in which it is removed from memory differs. Source: https://www.vadimbulavin.com/swift-memory-management-arc-strong-weak-and-unowned/
There are so many things happening in Swift that’s quite different from Objective-C and JavaScript/TypeScript, and in order to use it well, we have to understand the basic memmory first. I once had NSTimers running in Objective-C because I didn’t know it has reference to the view controller, so both didn’t get destroyed and I was bewildered for a while. So this is good to know (and very basic!). Also excited to be using functional programming on Swift!
More good resources:
- https://www.swiftbysundell.com/articles/property-wrappers-in-swift/
- https://www.vadimbulavin.com/value-types-and-reference-types-in-swift/
- https://www.vadimbulavin.com/unit-testing-best-practices-on-ios-with-swift/
- https://github.com/raywenderlich/swift-style-guide#lazy-initialization
Access level in swift. everything is internal
by default unless otherwise stated. Note private
-> fileprivate
-> internal
(default) -> public
/open
. So if your class
is public, to prevent accidents, implicility your members are all still internal
. For unit testing, we can access up to internal
if we mark it as @testable
(not clear yet on how unit testing work). If we have a tuple of mixed access type, the most restrictive one will be set. And no, we cannot set access level for tuple.
Naming!
Functions and methods are sometimes used interchangeably as both usable code and are defined by func
keyword, but in Swift, methods are functions that belong to a class
/struct
/enum
only, and it has self
. Of course we want functions like max
or zip
(which is like known/standard) but we wouldn’t want all our functions to be in the ‘public’ or ‘free’, since it’s like global(?) and polluting namespace(?).
Properties
Properties itself by definition are associated values for class/struct/enum.
Naming of properties
Swift has many kinds of properties it’s so confusing.. Seriously, please correct me if I am wrong.
First, variable vs property. This is basically same thing as the above functions/methods. They are all variables, but property is associated with class/struct/enum. Moving on.
Type Property - class
/enum
/struct
-level properties (read: static
that we are used to).
Instance Property - the usual instance we are used to when we “new
” an object in the heap/stack.
Now, for each of the above, they can be further categorised:
-
Stored Property - the usual variable we are used to. Note that
enum
cannot have stored property.- This can also be further categorised: Lazy Stored Property (
var
available only) - delay initialisation of the variable but multithreading can screw this up and init multiple times so need to beware!!! - You thought that’s all? NO!! Stored Property is upgraded to be easier than Objective-C, now we can observe and react based on
willSet
anddidSet
function. This is called Property Observer; they monitor changes and we can respond accordingly. You can access thenewValue
inwillSet
andoldValue
indidSet
in case you need it. More confusingly, if we are using this in a class situation, we can do it to our superclass and subclass too.
- This can also be further categorised: Lazy Stored Property (
-
Computed Property - basically think of it as a get function as they dont store property. counter-intuitively they also have a optional set function feature. Useful for e.g. computing a box’s center point given it’s origin and size on runtime. Like I said, getter/setter, but not good to go overboard with this, else just use it to call a function if it’s heavy.
- Hold up, the
willSet
anddidSet
in Stored Property applies to us too, but only for subclass classes’s Computer Property… IKR… - HOLD UP! Swift also introduced
get
andset
here too, and you cannot reference itself inside theget
andset
else there will be stack overflow as it kept going into a loop forever. So they have some named parameter likenewValue
forset
to use, kind of like in Objective-C we used_ivarXXX
as the intermediate variable.
Property Observer - similar to Computer Property, TBC…
- Hold up, the
Needless to say, static
properties cannot access any instance variables/functions.
More random(?) info:
- If you
let
a struct, you cannot change it’s properties even if they arevar
s, but you can do it forclass
object. Sincestruct
is value type, when we mark thestruct
instance itself as read-only, everything inside is read-only. Guess that make sense. mutating
keyword is for methods insidestruct
only. Cos we wantstruct
to be like immutable most of the time if possible but that’s not always possible. so we should treat mutating as a “red flag/warning” that could be potential for errors (which is the point ofstruct
, to prevent issues).- In Swift,
Array
,String
, andDictionary
are all value types.Set
, I don’t know. - Swift
init
is clearer and easier than Objective-C’s. No value return or noif (self)
nonsense. Purely to init vars. Forstruct
it is autogenerated unless you override it, forclass
andenum
too they have it. Property Observers are not called when we set directly the default value of the Stored Property or in ourinit
s. - In Objective-C/C/C++, enums are 0 by default and ints only. In Swift, you set it to what you want,
Int
,String
, and ‘autoconverting’ them by using the protocol likeString
to direct convert to string when you.rawValue
.
Protocols
It is similar to Objective-C (I think), but in ObjC it is mainly used for delegates kind of usage. So protocols are new things in Swift, and many say Swift is more like a protocol-oriented programming, and that seems to be the case from what I seen so far.
All class
/struct
/enum
can adopt protocols. Used it to separate (forgot what i wanted to say)
Protocols can inherit protocols too. class
/struct
/enum
can implement multiple protocols.
We can use it as a type itself but it’s very rare. We also can’t use it for View
, Equatable
, Identifiable
.
For generics, we can use it like struct MemoryGame<CardContent> where CardContent: Equatable
.
We can also use Protocol to restrict extensions, so that the extensions only apply for certain scenarios.
Goold old C++ operator overloading has made a comeback in Swift.
https://github.com/FiveStarsBlog/WWDCNotes is really good website for reading a summary of what’s new in WWDC.
Last updated: 19th Sept 2021. Will keep adding as I learn.