Ray Wenderlich Course Part 11 (up to lesson 101)
Yes! Managing to get in a couple of consecutive days of entries. Now, it would be easy to be disheartened after the Collections lessons, which were all very tricky! However, the comments confirm that they were confusing - not just to me. So I am going to plough on and try to get Structures done relatively quickly so I can move on to Classes next, then will be able to start the next project! That's the intention anyway!
I know that structures and classes bundle together information. They are similar however structures are used for values whereas classes are for objects. I also know that classes are a 'reference' type. These seem to be particularly important to make code more powerful and specific.
Structures
*This time I AM going to type and code along - it's the best way of getting something ingrained into your memory after all! AND I will use 'normal' speed.
So I did not type any of this - done already by Ray!
I know that structures and classes bundle together information. They are similar however structures are used for values whereas classes are for objects. I also know that classes are a 'reference' type. These seem to be particularly important to make code more powerful and specific.
Structures
*This time I AM going to type and code along - it's the best way of getting something ingrained into your memory after all! AND I will use 'normal' speed.
let restaurantLocation = (2, 4)
let restaurantRange = 2.5
// Pythagorean Theorem 📐🎓
func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int)) -> Double {
let distanceX = Double(source.x - target.x)
let distanceY = Double(source.y - target.y)
return sqrt(distanceX * distanceX + distanceY * distanceY)
}
func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool {
let deliveryDistance = distance(from: location, to: restaurantLocation)
return deliveryDistance < restaurantRange
}
So I did not type any of this - done already by Ray!
isInDeliveryRange(location: (x: 4, y: 3))
Right so this returns true, as it is within range of the the original location (2,4) an the range is 2.5. However, (5,4) would return false.
The issue here is that another location and range would mean the function gets very verbose and difficult to read....
struct Location {
let x: Int
let y: Int
}
struct DeliveryArea {
let centre: Location
let radius: Double
}
let restaurantLocation = Location(x: 3, y: 4)
let restaurantRange = 2.5
let restaurantArea = DeliveryArea(centre: Location(x: 4, y: 3), radius: 7.8)
Again, Ray has gotten too technical, so I'm skimming over the next bits.
*Interesting point here, variables are technically types of structs. This means that they are a value type - they hold the value they are given. There was the example of a = 5, b = a, then a changing value. B does NOT change value!
Challenge!
Here we go...not quite so excited as before!
// TODO: Write solution here
struct PizzaOrder {
let toppings: String
let size: String
let base: String
}
//: Change `distance(from:to:)` to use `Location`s as parameters instead of x-y tuples.
struct Location {
let x: Int
let y: Int
}
// TODO: Modify this
func distance(from source: Location, to target: Location) -> Double {
let distanceX = Double(source.x - target.x)
let distanceY = Double(source.y - target.y)
return sqrt(distanceX * distanceX + distanceY * distanceY)
}
//: Change `contains(_:)` to call the new `distance(from:to:)` with `Location`s.
struct DeliveryArea {
let center: Location
var radius: Double
func contains(_ location: Location) -> Bool {
// TODO: Modify this
let distanceFromCenter =
distance(from: center,
to: location)
return distanceFromCenter < radius
}
func overlaps(_ with: Location) -> Bool {
}
}
OK not too bad! I've been ok with it up until the most recent bit...will see if I can get any tips for this....
OK for the pizza one, it would have been better to have had a [String] array for the toppings and I didn't realise I needed to create an instance of one. That would have been fine!
func overlaps(with area: DeliveryArea) -> Bool {
return distance(from: center, to: area.center) <= radius + area.radius
}
}
So I got some but not all of that.
Protocols
These are a set of requirements that you must conform to. You need to do this to get the certain behaviour that you want. E.g. with the print statement for a protocol. Or storing to a dictionary...there are many!
Right, so many of the things in Ray's code just did not work. That's frustrating so I'm just going to move on.
Properties
Computed properties must ALWAYS be a variable.
struct Person {
var firstName: String
var lastName: String
var fullName: String {
return firstName + " " + lastName
}
}
var person = Person(firstName: "Josh", lastName: "Gonet")
person.lastName = "Groban"
person.fullName
OK, so the fullName property is a stored property. I cannot input anything into it as the firstName and lastName have already been put in upon declaration of person.
struct Person {
var firstName: String
var lastName: String
static var outOfWedlock = "Snow"
var fullName: String {
get {
return firstName + " " + lastName
}
set {
if let spaceIndex = newValue.index(of: " ") {
firstName = String(newValue[..<spaceIndex])
lastName = String(newValue[newValue.index(after: spaceIndex)...])
}
}
}
}
var person = Person(firstName: "Josh", lastName: "Gonet")
person.lastName = "Groban"
person.fullName
person.lastName = Person.outOfWedlock
person.fullName
OK so this is undoubtedly confusing. With the get and set, I'm not entirely sure so will see what else I can find out...
OK so something I got muddled was that firstName is a STORED property, whereas the fullName is a COMPUTED property. That makes more sense now. The fullName has to carry out some kind of code in order to get the value.
Lazy variables - you want code to run once and only once....not sure about these yet.
Challenge!
//: Create a struct named `Temperature` that contains a stored property `degreesF` that is a `Double`, which will store the degrees in Fahrenheit. Then add a computed property called `degreesC` that is a `Double`, that calculates the degrees in Celsius. Hint: `degreesC` should be equal to `(degreesF - 32) / 1.8`.
// TODO: Write solution here
struct Temperature {
var degreesF: Double {
didSet {
if degreesF > 100 {
print("Too hot!")
}
}
}
var degreesC: Double {
get {
return (degreesF - 32.0) / 1.8
}
set {
degreesF = (degreesC + 32) * 1.8
}
}
}
//: Modify the `degreesC` computed property to add a setter, so that by setting the degrees in Celsius, it actually updates the degrees in Fahrenheit.
// TODO: Modify code above
//: Modify the `degreesF` stored property to print out "Too hot!" if it is set to above 100 degrees Fahrenheit.
// TODO: Modify code above
Not too bad again - not sure about the 'set' part for the challenge...we shall see!
One error:
set {
degreesF = (newValue * 1.8) + 32
}
Needed the newValue keyword here!
You know what - great job! That was actually very close for the whole thing! :)
A real breakthrough in understanding here - what computed properties are!
Methods
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
struct SimpleDate {
var month: String
var day: Int
init() {
month = "January"
day = 1
}
init(month: String, day: Int) {
self.month = month
self.day = day
}
mutating func advance() {
day += 1
}
func monthsUntilWinterBreak() -> Int {
return months.index(of: "December")! - months.index(of: month)!
}
}
let testDate = SimpleDate(month: "February", day: 21)
testDate.monthsUntilWinterBreak()
A lot of this is familiar, which is great. The mutating keyword is needed as it is going to change the value of one of the properties (day).
Challenge
This looks tricky!
//: Create a structure named `Student` with three properties: first name, last name and grade. Then create a structure named `Classroom` with two properties: the class name, and an array of students. Finally, create a method named `highestGrade()` that returns the highest grade in the classroom. Try using `reduce` on the array to perform the calculation.
// TODO: Write solution here
struct Student {
var firstName: String
var lastName: String
var grade: Double
}
struct Classroom {
var className: String
var students: [Student]
func highestGrade() -> Double {
return students.reduce(0) { result, student in
return student.grade > result ? student.grade : result
}
}
}
//: Make an extension on classroom with a method named `curveGrades()`. This method should find the difference between 100 and the highest grade, and add this amount to all students scores. Finally, sort the students array so they are ordered from the students with the highest score, to the students with the lowest score.
//:
//: **Hint**: remember that structures are value types, so if you iterate with `for student in students` you'll get a constant copy of the student, not the student inside the array. Is there another way you can loop through the students in the array?
// TODO: Write solution here
extension Classroom {
mutating func curveGrades() {
let curveAmount = 100.0 - highestGrade()
for i in 0..<students.count {
students[i].grade += curveAmount
}
students.sort { student1, student 2 in
return student1.grade > student2.grade
}
}
}
I needed a LOT of help for most of this. It's too hard!!!
Again, it's discouraging to see myself finding lots of this stuff so difficult. Yet, I know that it's been pitched too high - there are so many conceptual leaps. Closures are mind boggling, as are a lot of the methods that Ray uses with Arrays and loops. Anyway, I've had a go and have picked up some useful nuggets.
- Variables are structure types - they are values that hold their own
- Structures are VALUE types
- They are NAMED types - they have a specific name (unlike Int, String etc.)
- Stored properties are inputted whereas computed ones are coded in some way
- The get/set links to the above. Computed properties have to be 'get'-ed and can have a 'set' value e.g. if the stored property gets changed.
- The didSet/willSet is a bit more confusing but I know that didSet means if a value has been inputted - there will be a condition and outcome attached
So it hasn't been a total waste of time! Still I just want to crack on with the next project, which will hopefully clarify a lot of the information that just boggles my mind at the moment. HOWEVER, I will complete the 'classes' series of lessons tomorrow as I simply must for a) completist sake and b) there may well be useful things there too.
Comments
Post a Comment