Bob Lee Course Part 17 (Lecture 29)
Unusual time to be doing an entry? Yes, absolutely! I have laryngitis - so I basically have to be off work, both yesterday and today. A blessing? Probably! Well, the upshot is that I get to do some coding today, a rare treat. It's been difficult finding any time recently due to going to the F1 in Abu Dhabi, work and laryngitis! So, let's pick that up with Bob's course. Last time it was an introduction to closures. It was hard! From what I remember, closures are another way of writing functions. They can actually be simpler - VERY simple if you use the $ syntax for accessing the values. Still, the whole thing was tricky. Let's continue with the aim of finishing Chapter 3 today!
Start Time - 11:27
Lazy Init with Closures
My take - I know a bit about lazy already. I know that this means the value does not take up any space until it is used. So it is good for memory management.

So that is the code for creating a UIButton. Bob's point here is that to create a second bobButton, you would be repeating yourself - using the same code copied and pasted then tweaked. This goes against the DRY principle!
Here is creating a function that would create a button:

But the code would get complex with all of the various parameters needed.
Basically the code here in general is tedious and verbose.
So creating a UIView includes using closures. I've followed along but not sure where this is going yet...

Ok, interesting - Bob states that he has a whole LIBRARY of this code written out, that he can just copy and paste to get buttons/UI objects. Then he can just tweak the properties. OK, making a bit more sense!
Right, so 'lazy' is used because it doesn't do it straight away. When it does do it, it only happens once. OK, that makes a little more sense. I'm still a bit lost with the closure syntax - I need more practise with that basically.

In this example, we don't want to do the sortNumber closure straight away. So lazy is used. You don't want to have this method every time - only when the user actually needs it. Good also for compressing images - takes a lot of work so lazy is useful for this.
The CONCEPT of lazy is getting clearer to me. Bob keeps saying to go back and learn the syntax, but that's easier said and done. What I need is to look at another course, specifically for simple closure stuff, just to get the grasp of the language/syntax of that before doing another Bob course.
Rules of lazy -
Start Time - 11:27
Lazy Init with Closures
My take - I know a bit about lazy already. I know that this means the value does not take up any space until it is used. So it is good for memory management.

So that is the code for creating a UIButton. Bob's point here is that to create a second bobButton, you would be repeating yourself - using the same code copied and pasted then tweaked. This goes against the DRY principle!
Here is creating a function that would create a button:

But the code would get complex with all of the various parameters needed.
Basically the code here in general is tedious and verbose.
So creating a UIView includes using closures. I've followed along but not sure where this is going yet...

Ok, interesting - Bob states that he has a whole LIBRARY of this code written out, that he can just copy and paste to get buttons/UI objects. Then he can just tweak the properties. OK, making a bit more sense!
Right, so 'lazy' is used because it doesn't do it straight away. When it does do it, it only happens once. OK, that makes a little more sense. I'm still a bit lost with the closure syntax - I need more practise with that basically.

In this example, we don't want to do the sortNumber closure straight away. So lazy is used. You don't want to have this method every time - only when the user actually needs it. Good also for compressing images - takes a lot of work so lazy is useful for this.
The CONCEPT of lazy is getting clearer to me. Bob keeps saying to go back and learn the syntax, but that's easier said and done. What I need is to look at another course, specifically for simple closure stuff, just to get the grasp of the language/syntax of that before doing another Bob course.
Rules of lazy -
- You can't use lazy with let. There's no initial value - it's gotten later when accessed
- Can't use it with a computed property. CP require computation - when any values are changed, recalculation is used and that goes against the lazy principle
- Lazy is only valid for members of a class or struct. So I can't use it anywhere else
A good time for a pause there.
Paused at 11:55 (28 minutes so far)
I'm pausing for a couple of reasons. First I need to eat a little something, then pop out to the tailors. Also, I need to add to this entry some general practice of syntax with closures. The information has little context unless I get that! So, before I go on to the next Bob lecture, I'm going to see out some closure practice from somewhere....
Restarted at 12:32
So I'm using 'We Heart Swift' - a site I used in the early days of learning Swift. I stopped using it after some of the loops challenges became very repetitive and tedious. Anyway, it was a great way to apply some of the knowledge so let's see what it says about closures...
https://www.weheartswift.com/closures/
Right so first bit confirms the similarity between closures and functions. Technically - and Bob did say this before - that functions are a type of closure! Interesting. There are three types:
Global - have a name and cannot capture any values
Nested - have a name and can capture closures from their enclosing functions
Closure expressions - don't have a name but can capture values from their context
Right...
var hello: () -> (String) = {
return "Hello!"
}
var double: (Int) -> (Int) = { x in
return 2 * x
}
So each time, a var is used. Yes I get that. You need to declare the type or an empty parentheses if nothing is going IN. The return after the -> is the type coming out. Ok I got that. Let's practise some more...
var greetingForName: (String) -> (String) = { name in
return("Greetings \(name)")
}
greetingForName("Josh")
Fantastic! I adapted the hello and created my own. Key thing about the syntax here - you don't put parameters here but put need to use the value and the in key words at the start of the closure expression.
var square: (Int) -> (Int) = { number in
return number * number
}
An easy adaptation from the We Heart Swifts double...
var total: (Int, Int, Int) -> (Int) = { (number1, number2, number3) in
return number1 + number2 + number3
}
total(1, 2, 3)
Ok, that's cool - using multiple inputs.
var numbers = [1, 4, 2, 5, 8, 3]
numbers.sort(by: <)
Right the sort method is a closure.
numbers.sort(by: { x, y in
return x < y
})
OK here is a clearer closure used. The x and y values are just arbitrary parameters to put in to return the x < y statement.
So here is a way of showing the difference with the parameters and return values. It makes it a bit clearer. Let's break it down.
First one - no parameter shown by nothing in first brackets and the nothing returned is nothing in the second brackets. OK.
Second one - no parameter and this time the TYPE is in the return brackets - so we know an int is being returned.
Third one - one parameter (one Int) and return (Int) then because we have a parameter, we need to use in keyword as well as return.
Fourth one - two Strings as parameters. Need to put in what these parameters are called. Also we have multiple arrows - so that means we are going to return a String, then another one...
Right to simplify these:
The first one does NOT need the empty brackets. The second one does not need the first brackets. The third one is simplified too as is the last one - that makes more sense for what you actually need.
The shorthand for the sum/total closure:
var sum: (Int, Int) -> Int = {
return $0 + $1 }
So $0 is the first parameter, $1 is the second and so on. This removes the need for parameter names AND the use of the in keyword.
Another key point is that closures are REFERENCE types. That means that if several different values are assigned to the same closure, then the value of the closure will change when each value assigned to it does.
Challenge 1 - really hard!
func applyKTimes(_ K: Int, _closure: () -> ()) {
for _ in K {
closure()
}
}
Right, I've tried some other challenges but they're just too confusing. Time to check another source for closures!
*Pause for 10 minutes
OK I've found something from Stephen DeStefano Course... Let's see if it's useful!
Closures are a self-contained block of functionality that can be passed around within the code.
I'm going to pause there while I have lunch!
Paused at 13:37
Continued at 14:15
So closing over/capturing a value is what closures can do.
Right so there are the three types of closures. That helps to clarify it a bit.
func reverseSortString(string1: String, string2: String) -> Bool {
return string1 < string2
}
reverseSortString(string1: "Josh", string2 "Cath")
Ok so that works, but I can't put in this function to the sort method on Xcode. Must have updated since Stephen's course!
var reverseSorter = {(string1: String, string2: String) -> Bool in return string1 > string2}
Right there is my closure that does the same as the function. I know where this is going with the dollar signs...
var newReverse: (String, String) -> Bool = {
return $0 > $1
}
There - did that without Stephen's help, just checked some previous code I did!
var descendingOrder = newNames.sort(by: {$0 > $1})
for name in newNames {
print(name)
}
OK that does work with an array of names. Cool.
Ahhhh this is back to the start really! I don't need the difficult closure for that - just a > sign! That's what Bob was showing initially!
Ok now checking out the main Apple site, as Stephen's did not majorly help.
So according to the main site on closures, there are three types: global functions, nested functions and closure expressions. It's the latter I need to get my head around more.
It does the sorting reverse example, going bigger with String, String returning Bool to simply a > b to eventually just >.
Here is the clear closure expression for using one within the sort method:
var reversedNames = newNames.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
So that gives me more of an idea of what a closure expression is at least.
Found another good source:
https://learnappmaking.com/closures-swift-how-to/#how-to
Reindeer (if that is his real name...) explains what closures are with a couple of analogies. OK, so it makes a little more sense.
So key differences with closures and functions:
- Parameters are NOT NAMED!
- In the closure expression is where naming the parameter happens - a local variable (or you can use the $0 for the first/only value!)
- Type inference - this is crucial for simple, logical closures
- Closing over, capturing, enclosing - all means the same thing!
Finish Time - 15:12 (2 hours 20 minutes!!)
Right, so mind is still perplexed by these closures. The fact is that I've spent a LONG time on it today and am still unsure about quite a bit. BUT, I definitely know more now than I did! So I'm leaving it there. Next I'm going to go back to my Xcode project - need to crack on with that. Then I will resume with the rest of Bob's Chapter 3 and hope some sinks in!
Comments
Post a Comment