- ViewModel is never calling View but View calls ViewModel
- One ViewModel can be used by many Views and that is why it's a class
- Holding
option
and clicking a variable name allows to do all kind of things like rename. -
mutating
keyword is used front offunc
when it's changingself
- in
struct EmojiMemoryGameView: View {
View
is called protocol (constrains and gains). The idea is that we gain something (functions) from using it but it also contrains us to do something like havevar body: some View
Reactive
-
ObservableObject
is constraint and gain that gives a class (ViewModel) ability to follow changes. Every time something changes it updates the UI.-
objectWillChange.send()
is can be added to functions where some object will change. - It's more common to add
@Published
property wrapper front of the variables that will change because that way you don't forget to addobjectWillChange.send()
to some position.- Behind the scenes it checks that every time that variable is changes it calls
objectWillChange.send()
- Behind the scenes it checks that every time that variable is changes it calls
-
-
@ObservedObject
is added front of ModelView in View class to redraw it every time the ModelView changes. -
protocol
is like stuct/class that can contain vars and functions but it doesn't had implementation to them.- Classes and structs can use
protocol
following wayclass Car: Vehicle
It's possible to implement multiple protocols by separating them with commas. - Protocols can also inherit other protocols
protocol Vehicle: Moveable ...
- protocol offers constrains and gains
- The idea in protocols is that multiple structs/classes can use it and then if it's extended all of them get the new feature
- Classes and structs can use
-
extension
is used to add new functionalities to structs, classes, protocols - Protocols are useful because they say what the types (structs/classes/other protocols) are capable of and also demand certain behavior.
protocol Greatness {
func isGreaterThan(other: Self) -> Bool
}
extension Array where Element: Greatness {
var greatest: Element {
// for-loop through all the elements
// which (inside this extension) we know each implementes the Greatness protocol
// and figure out which one is greatest by calling isGreaterThan(other:) on them
return the greatest by calling isGreaterThan on each Element
}
}
-
Self
means that type comes from the thing that is implementing that protocol.
Layout (49:57)
- HStack and VStack
- Offers space to its "least flexible" subviews first
- Image: "inflexible"
- Text: "slightly more flexible"
- RoudedRectangle: "flexible"
- Defaults work a little bit differently in different devices and that is why we should keep them and not put specific numbers because those probably doesn't work as many device
-
Spacer
takes the space given and draws nothing -
Divider
Draws line (horizontal or vertical depending the stack)
- Offers space to its "least flexible" subviews first
HStack {
Text("Important").layoutPriority(100)
Image(systemName: "arrow.up") // default layout priority is 0
Text("Unimportant")
}
- Important text takes the space it wants
- Then image takes the space it wants
- Finally Unimportant text takes the remaining space
Demo (1:12:04)
struct CardView: View {
GeometryReader { geometry in
ZStack {
if self.card.isFaceUp {
RoundedRectangle(cornerRadius: 10.0).fill(Color.white)
RoundedRectangle(cornerRadius: 10.0).stroke(lineWidth: 3)
} else {
RoundedRectangle(cornerRadius: 10.0).fill()
}
}
.font(Font.system(size: min(geometry.size.width, geometry.size.height) * 0.75))
}
It's common to move the numbers to a "control panel". In one place it's easy to modify them and the main code becomes cleaner.
Top comments (0)