Bob Lee Course Part 9 (Consolidation of chapter 1 - lectures 1 to 15!)

Yes, it's time for some consolidation baby! I could just do so for the past few lectures but it makes more sense to go through chapter one in its entirety. If anything does seem really familiar, that's fine - I will obviously spend less time on that! OK, here we go!

Start Time - 17:35

Lecture 1 - Course Overview (skipped!)

Lecture 2 - Introduction

Key tip to takeaway from this summary is NOT just to click on the 'fix errors' when the 'red' errors come up. They can lead to more errors and mess up the code - then be impossible to track back and sort out!

Lecture 3 - Optionals

So the big question here is WHY use optionals in the first place. Something to remember here is that Swift is the only language (well, one of the very few at least) that uses optionals. They are a great feature!

*Right, rather than play the videos again, I am actually going to use Bob's lecture notes from here:

https://www.bobthedeveloper.io/course/swift/1000-swift-fundamentals/1001-optionals


A more concise approach! I'm also using my notes from before to check anything.

Two key rules:

  1. Every variable type must be defined (Implicit/Explicit)
  2. The type is inferred based on the value
Right, so I tend to use implicit declaration for 1. And that means that 2. is figured out. The key thing here I guess is that optionals NEED explicit declaration. 

A good real-life link:









Yes so in the above, the second line would cause the program to crash. This is for uploading a Facebook profile picture. 

Right more key rules that I did not have totally clear before. Normal and optional types CANNOT interact with each other. I could not for example add an optional Int to a normal Int and get a value. 
That means unwrapping is required! 

Unwrapping

Two types of unwrapping - forced and implicit. Forced unwrapping is NOT advised though it does happen occasionally. The issue here is if nil is the value, then that can not be converted to a normal type. It will crash! That's why implicit is preferred. 

Implicit is the if/let statement. That I'm 100% fine with. Moving on!

Lecture 4 - Optional Chaining

So this is all about why we use ? and !. 

This lecture basically shows the example with a custom type (Human)...






















That's just a very straightforward custom type being created. Here's where the optional comes in....











So the point of this is that creating an object from the Human class, the ? will get put in because it is an optional type, not a normal type. If/let as before can be used to implicitly unwrap. Cool. 

Lecture 5 - Guard and Defer statement

I like the guard statement.  This is Bob's analogy to do with 'zen'. It promotes nothingness. So it would go to the else bit first. It's better than else/if because every line of code is needed to spot the error message and there can be nested statements (statements within statements...)

Here's the example I used before...

let myName: String? = nil

func stringCheck() {
guard let name = myName else {
    print("There is no value")
return
    }
    print(name)
}
With this, it is WITHIN a function! I've never seen a guard outside of a function. It's the return keyword I think.

Multiple values unwrapping...

func unwrap() {
    if let name = driverNamelet car = driverCarlet wins = driverWins {
        print("Driver is \(name), who drives for \(car) and has won \(wins) races")
   } else {
        print("Error")
}

func guardUnwrap() {
    guard let name = driverNamelet car = driverCarlet wins = driverWins else {
        print("something is missing")
        return
    }
    print("Driver is \(name), who drives for \(car) and has won \(wins) races"
}

In these two examples, the first one is with the if/let; the second is guard/let.

MUCH better than doing nested if/let statements!

Not much advantage of guard over if/let - it's just that it goes to the error message first. The advantage I guess is spotting the error message first, rather than reading all of the code first. 


And the last bit - defer statement...

Right, it just means - this will be done last! An example with a loop...




















Interesting - but not sure when I will ever use a defer statement!

Paused at 18:10 (35 minutes so far)

Restart at 19:07

Lecture 6 - Intro to Error Handling

OK, back! 

Looking over the first part of Bob's notes, he really helped to make clear the fact that error handling is purposefully for BUILT IN POTENTIAL ERRORS! This was never clear to me before, when I did the Treehouse course on it. 

Anyway, let's just check over this!

So it can be done with a built in function that has an if/let or guard/let statement. The issue with this is that it becomes 'bloated', lacks 'modularity' (not conventionally recognised in the trade as specific error handling) and there is still uncertainty. 

Basically it is better to use the enum to create the type of errors you want. The enum needs to conform to the Error protocol (so it adopts that behaviour when called essentially). 

Throwable function

This is a function that uses the 'throws' keyword at the end of it (instead of an arrow/return). 

Here is the example I used before:

func checkHeightError(height: Int) throws {
    
    if height > 200 {
        throw ErrorMessage.maxHeight
    } else if height < 140 {
        throw ErrorMessage.minHeight
    } else {
        print("All is good!")
    }

So that is a throwable function BY DESIGN!

Calling and handling an error

Right this is where 'do', 'try' and 'catch' come in. 

THIS IS FOR SPECIFIC ERROR TESTING!!!

do {
    try checkHeightError(height: 20)
catch ErrorMessage.minHeight {
    print("You are too short!")
catch ErrorMessage.maxHeight {
    print("You are too tall!")
}

Classes 

You can also bring in the throwable element within the init of a class. Neat.

*Of course you need the enum with error message created beforehand. 

Another way of testing for errors - 

do {
    let newCourse = try Course(name: "")
catch NameError.noName {
    print("You need to enter your name!")
} 

So this one tests to see if there is no value given to the name property of the Course class object. 

Try, Try?, Try!

There is a Smashing Pumpkins song called this! Not with the ? and ! of course. 

Try - used within the do/catch block specifically

Try? - used to test optional values. An optional type will be returned (even if nil). 

E.g. 

let newCourse = tryCourse(name: "")

Try! - as expected, if there is a value it will return a normal type. But as before, if nil then the program will crash...

So, just to clarify that, you ONLY use try within a do/catch block. Try? and Try! are used separately to this. This makes much more sense! Glad I am going over this!!


Lecture 7 - Type Casting

OK I remember this pretty well - the use of up/down casting. Basically 'any' type includes string, Int etc. So upcasting those to any is one way. This is also used with custom types. Let's have a look!

Custom types

let newBob = bob as Human

It's as easy as that if there is a parent/base class!

Normal types

Technically Ints and Strings are structures as they are VALUE types. So they will be upcasted to 'Any'. 

Downcasting

The issue with this is that it could fail e.g. if "Josh" was attempted to be downcasted from any to string. So, like optionals, this is where the ? and ! come into it! Implicit and forced. 

The example for up/down casting for Any is in my other blog(s) on that. So not going to go into massive detail. Basically, an Array can be used with each value (after each has been put as 'any'), then each item can be accessed with the index system, to then be put as an Int/String etc. 


var name = "Josh" as Any

var number = 33 as Any

var anArray = [namenumber]

let newerNumber = anArray[1asInt

This would of course make an optional which is SAFER. The as! would force unwrap - as usual. Good.

Another cool part of Upcasting

I could create load of objects of various subclasses, all of which can be attributed (however many steps) to a particular parent class. THEN create the array with them all in - they will ALL automatically convert to the associated parent class. Nice!

Lecture 8 - Generics

This is basically using 'any' as a type in the code. Let's remind me!

Right, the beauty of these is that it doesn't matter WHAT type is used for a specific function. It uses 'anything' rather than any. 

func printElement<T>(array: [T]) {
    for element in array {
        print(element)
    }
}

So this function above means that any array of any type can have its elements printed. <T> is used conventionally instead of 'anything'. T = Type. 

You can use extensions and type constraints - but I won't go into massive detail. I can come back to these!
* I am taking what I need from generics for now!

Lecture 9 - Subscripts

So these are a) shortcuts and b) something I'm struggling to make sense of. 

Need to find out more online....

It seems to be useful for rows/columns and is used alongside get/set. OK. Let's come back to that another time!


Lecture 10 - Class vs Struct

I'm fine with this.

An interesting points - constants with classes are actually mutable. Not structs though. 

I get the whole reference vs value thing. 


Lecture 11 - Sets and Tuples

Sets - can't have duplicate items. The < > syntax is used. 

All of these were examples from before:

var setOne: Set = [123]

var setTwo: Set<String> = ["Josh""Cath""Alex"]

var setThree = Set<String>()

var setFour = Set(["Josh""Cath""Alex"])


So the set keyword is used every single time. 

You can convert between array/set. 

var oddNumberSet = Set(oddNumbers)
let evenNumberSet = Set(evenNumbers)

There are also different features sets can do when looking at two sets of the same type. 






















Intersection looks most useful - used for fizz buzz maybe?

But can be used for strings too of course. 

Tuples - good for error types (a number and string together). 


Lecture 12 - Extensions

Right so you can extend custom types. You cannot add in stored properties though - only computed ones!

You can also extend the main/native types in swift e.g. with Int, you can add a squared method. 




Lecture 13 - Intro to Operators

I remember this. Unary is e.g. !true - uses one target; binary is e.g. 5 + 4 (two targets); tertiary is obviously 3. 

Tertiary is the same as an if statement. 

Or is it ternary?

Ternary I think!

let watchSimpons = true

watchSimpons ? print("Which episode?") : print("No Simpsons!")


for number in 1...50 {
    
    number % 2 == 0 ? print("\(number) is a multiple of 2") : print ("\(number) is not a multiple of 2")

}

Good examples using the ?

Nil coalescing operator

var driverWins: Int? = nil

var minimumWins = 5


var newWinsRecorded = driverWins ?? minimumWins

Another good example of less is more! 

newWinsRecorded - new variable to store the value

If the optional (always on the left of the ??) has nil, then the value on the right (minimumWins) is used

If the optional does contain a value (driverWins), then that value is assigned to the new var. 

Cool!


Lecture 14 - Type Alias

Last one! Phew! So this is creating fake names for things. That's it. Right... so we could use 'Name' instead of 'String'. Then refer to 'Name'. 

Not an awful lot of point but I know what it is!

Lecture 15 - Conclusion


THAT'S IT!

A very quick recap...

Optionals - I know get the purpose of these and why they are deliberately created. The unwrapping makes more sense now, using forced (avoid!) and implicit (safe - three ways). Defer statement - weird but I get that it's the last thing that is read.

Error Handling - makes much more sense that a) these are built in by design and b) can be tested in several ways. Try, try?, try! all make more sense. 

Type casting - seem less practically useful than the above but I understand up/down casting and how as is used (plus as? as!). 

Generics - code that can be applied to any type. <T> is used customarily. Good when using the same function e.g. elements of an array that can be of multiple types. 

Subscripts - don't get the point of these yet. Supposed to be shortcuts. 

Class vs struct - reference vs value etc. etc. Good point about classes are actually mutable for constants (unlike value types). 

Sets/tuples - the former are great for comparing sets of data. Specific syntax of 'Set' used. Tuples - combining different types is cool e. g. for error messages. 

Extensions - custom or native types can be added to in terms of functionality etc. 

Operators - use of the ternary instead of if statement; nil coalescing for optionals - really cool. 

Type Alias - seems pointless!

Finish Time - 20:19 (1 hour 12 minutes)

1 hour 47 minutes total for this entry


And there we go! Time very well spent. All of those concepts are much, much clearer in my head. I'm trying to get to the 'OWN IT' level! Only two I don't get and do need to read up on (at some point...) are subscripts and type alias. 

All done! Will be continuing with Bob's course by commencing Chapter 2 during the week!


Comments

Popular posts from this blog

*Xcode Project Entry 2* F1 Quiz - part 1

Angela Yu Course Part 10 (up to lesson 112)

Angela Yu Xcode 12 Course - Part 7 (lectures 74 to 79)