0% found this document useful (0 votes)
10 views

Lec04_01 (MVVC&SwiftUI)

The document outlines the CIS651 Mobile Application Programming course, focusing on the MVVM design paradigm and SwiftUI layout. It includes course updates, assignment details, and various SwiftUI property wrappers such as @State, @StateObject, and @ObservedObject. Additionally, it explains the differences between structs and classes, generics, and the concept of functions as types in Swift programming.
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Lec04_01 (MVVC&SwiftUI)

The document outlines the CIS651 Mobile Application Programming course, focusing on the MVVM design paradigm and SwiftUI layout. It includes course updates, assignment details, and various SwiftUI property wrappers such as @State, @StateObject, and @ObservedObject. Additionally, it explains the differences between structs and classes, generics, and the concept of functions as types in Swift programming.
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 48

CIS651: Mobile Application Programming

MVVM
SwiftUI Layout

Dr. Hong Martel


[email protected]

Acknowledgement:
For online CIS193 course slides published by Stanford
University
Course Updates
■ HelloSwiftUI-Env.zip App Demo updated with
@State
@StateObject
@ObservedObject
@EnvironmentObject
Application Icon
■ Assignment 01 uploaded, due 02/03/2024
Question Of the Day – Password:

Online Swift Complier:


https://www.tutorialspoint.com/
compile_swift_online.php
Show two ways of creating an empty array of integers.
Architect
MVVM
Design paradigm
ure
Varieties of Types
struct
class
protocol
“Dont’
Care”
type (aka
generics)
enum
functions
MVVM
Model-View-ViewModel
A “code organizing” architectural design paradigm.
Works in concert with the concept of “reactive” user-interfaces.
Must be adhered to for SwiftUI to work.
It is different from MVC (Model View Controller) that UIKit (old-
style iOS) uses.
MVVM

Model View

UI Independent
Data + Logic
“The Truth”
MVVM

Model data flows this way (i.e. read-only) View

UI Independent Reflects the


Data + ModelStateles
Logic s
“The Truth” Declare
d
Reactive
MVVM
ViewModel

Binds View to Model


Interpreter

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
Declared
Reactive
MVVM
ViewModel
s
nge
a Binds View to Model
ch
es Interpreter
tic
no

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
Declared
Reactive
MVVM might
“interpret”

ViewModel
s
nge
a Binds View to Model
ch
es Interpreter
tic
no

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
Declared
Reactive
MVVM might
“interpret” publishes “something
changed”
ViewModel
automatica
s lly
nge
a Binds View to Model observ
ch
es Interpreter es
tic
no publication
s, pulls
data and
Model Viewrebuilds

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
Declared
Reactive
MVVM
ObservableObject
@Published might
“interpret” publishes “something
objectWillChange.send() changed”
.environme ViewModel
ntObject() automatica
s lly
nge
a Binds View to Model observ
ch
es Interpreter es
tic
no publication
s, pulls
data and
Model Viewrebuilds
@ObservedObject
UI Independent @Binding Reflects the Model
Data + Logic .onReceive Stateless
“The @EnvironmentObject Declare
Truth” d
Reactive
MVVM
ViewModel

Binds View to Model


Interpreter

Model View

UI Independent Reflects the


Data + ModelStateles
Logic s
“The Truth” What about the other Declare
direction? d
Reactive
MVVM
ViewModel

Binds View to Model


Interpreter
Processes Intent

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
What about the other Declared
direction? Reactive
MVVM
call
s In
tent
func
ViewModel tion

Binds View to Model


Interpreter
Processes Intent

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
What about the other Declared
direction? Reactive
MVVM
l call
s In
Mode tent
s th
e func
m odi e
fi ViewModel tion

Binds View to Model


Interpreter
Processes Intent

Model View

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
What about the other Declared
direction? Reactive
MVVM might publishes “something
“interpret” changed”
call
l s In
Mode tent
s th
e func
m odi e
fi ViewModel tion
automatica
s lly
nge
a Binds View to Model observ
ch
es Interpreter es
tic
no Processes Intent publication
s, pulls
data and
Model Viewrebuilds

UI Independent Reflects the Model


Data + Logic Stateles
“The Truth” s
Declared
Reactive
MVVM
ObservableObject
@Published

objectWillChange.send() might publishes “something


.environme “interpret” changed”
call
l s In
ntObject() Mode tent
the func
mo
difies ViewModel tion
automatica
s lly
nge
a Binds View to Model observ
ch
es Interpreter es
tic
no Processes Intent publication
s, pulls
data and
Model Viewrebuilds
@ObservedObject

UI Independent @Binding Reflects the Model


Data + Logic .onReceive Stateless
“The Truth” Declared
@EnvironmentObject
Reactiv
e
Architect
MVVM
Design paradigm ure
Varieties of Types
struct
class
protocol
“Dont’
Care”
type (aka
generics)
enum
functions
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
var isFaceUp: Bool
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
computed vars (i.e. those whose value is the result of evaluating some code)
var body: some View {
return Text(“Hello World”)
}
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
computed vars (i.e. those whose value is the result of evaluating some code)
constant lets (i.e. vars whose values never change)
let defaultColor = Color.orange
. . .
CardView().foregroundColor(defaultColor)
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
computed vars (i.e. those whose value is the result of evaluating some code)
constant lets (i.e. vars whose values never change)
functions
func multiply(operand: Int, by: Int) ->
Int { return operand * by
}
multiply(operand: 5, by: 6)

func multiply(_ operand: Int, by otherOperand:


Int) -> Int { return operand *
otherOperand
}
multiply(5, by: 6)
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
computed vars (i.e. those whose value is the result of evaluating some code)
constant lets (i.e. vars whose values never change)
functions
initializers (i.e. special functions that are called when creating a struct or class)
struct MemoryGame {
init(numberOfPairsOfCards: Int) {
// create a game with that many pairs of cards
}
}
struct and
Both struct
class
and class have …
… pretty much exactly the same syntax.
stored vars (the kind you are used to, i.e., stored in memory)
computed vars (i.e. those whose value is the result of evaluating some
code) constant lets (i.e. vars whose values never change)
functions
initializers (i.e. special functions that are called when creating a struct or
class) So what’s the difference between struct and class?
struct and
class
■ Struct ■ Class
■ Value type ■ Reference type

■ Copied when passed or assigned ■ Passed around via pointers

■ Copy on write ■ Automatically reference counted

■ Functional programming ■ Object-oriented programming

■ No inheritance ■ Inheritance

■ “Free” init initializes ALL vars ■ “Free” init initializes NO vars

■ Mutability must be explicitly stated ■ Always mutable


■ Used in specific circumstances in SwiftUI
■ Your “go to” data structure
■ The ViewModel in MVVM is always a
■ Everything you’ve seen in SwiftUI examples so far
class
is a struct
■ UIKit (old style iOS) is class-based
(except View which is a protocol)
Generics
Sometimes we just don’t care
We may want to manipulate data structures that we are “type agnostic” about.
In other words, we don’t know what type something is and we don’t care.
But Swift is a strongly-typed language, so we don’t use variables and such that are “untyped.”
So how do we specify the type of something when we don’t care what type it is?
We use a “don’t care” type (we call this feature “generics”) …
Generics
Example of a user of a “don’t care” type: Array
Awesome example of generics: Array.
An Array contains a bunch of things and it doesn’t care at all what type they are!
But inside Array’s code, it has to have variables for the things it contains. They need types. And
it needs types for the arguments to Array functions that do things like adding items to it.
Enter … GENERICS.
Generi
How Array
cs
uses a “don’t care” type
Array’s declaration looks something like this …
struct Array<Element> {
.. .
func append(_ element: Element) { . . . }
}
The type of the argument to append is Element. A “don’t care” type.
Array’s implementation of append knows nothing about that argument and it does not care.
Element is not any known struct or class or protocol, it’s just a placeholder for a type.
The code for using an Array looks something like this …
var a =
Array<Int>()
a.append(5)
a.append(22)
When someone uses
Array, that’s when
Element gets
determined (by
Array<Int>).
Generics
How Array uses a “don’t care” type
Array’s declaration looks something like this …
struct Array<Element> {
.. .
func append(_ element: Element) { . . . }
}
Note that Array has to let the world know the names of all of its “don’t care” types in its API.
It does this with the < > notation on its struct declaration Array<Element> above.
That’s how users of Array know that they have to say what type Element actually is.
var a = Array<Int>()
It is perfectly legal to have multiple “don’t care” types in the above (e.g. <Element, Foo>)
Generics
Type Parameter
We will often refer to these types like Element in Array as a “don’t care”
type. But its actual name is Type Parameter.
Other languages most of you may know (e.g. Java) have a similar feature.
However, Swift combines this with protocols to take it all to the next level.
We’ll talk about this later!
Functions as
Types
■Functions are types
■You can declare a variable (or parameter to a func or whatever) to be of
type “function”. The syntax for this includes the types of the arguments
and return value.
■You can do this anywhere any other type is allowed.

■Examples …
(Int, Int) -> // takes two Ints and returns a Bool
Bool (Double)-> // takes a Double and returns nothing
Array<String> // takes no arguments and returns an Array of Strings
() -> Void
() -> Void // takes no arguments and returns nothing (this is a common one)
All of the above are just types. No different than Bool or View or Array<Int>. All are
types.

var foo: (Double) -> Void // foo’s type: “function that takes a Double, returns nothing”
func doSomething(what: () -> Bool) // what’s type: “function, takes nothing, returns Bool”
Functions as
T ypes
Functions are types
Example …
var operation: (Double) -> Double
This is a var called operation.
It is of type “function that takes a Double and returns a Double”.

Here’s a simple function that takes a Double and returns a Double …


funcsquare(operand: Double) ->
Double { return
operand * operand
}

operation = square // just assigning a


value to the operation var, nothing more
let result1 = operation(4) // result1
would equal 16
Note that we don’t use argument labels (e.g. operand:) when executing function types.
operation = sqrt // sqrt is a built-in function which happens to take and return a
Double
let result2 = operation(4) // result2 would be 2
We’ll soon see examples of using a function type for a parameter to a function in our demo.
Functions as
Closures Types
It’s so common to pass functions around that we are very often “inlining” them.
We call such an inlined function a “closure” and there’s special language support for it.
We’ll cover this in the demo and again later in details.

Remember that we are mostly doing “functional programming” in SwiftUI.


As the very name implies, “functions as types” is a very important concept in
Swift.
Very.
SwiftUI Property Wrapper
@State
o Belong to a specific class and never get used outside that
class
o Local, make it private
import SwiftUI

struct ContentView: View {


@State private var showingAlert = false
var body: some View {
VStack {
VStack {
Button(action: {
self.showingAlert = true
}, label: {
………………
SwiftUI Property Wrapper
@State
o When the state changes, SwiftUI knows to automatically
reload the view with the latest changes to reflect the new
state
struct ButtonTapView: View {
@State private var tapCount = 0

var body: some View {


Button("Tap count: \(tapCount)") {
tapCount += 1
}
}
}
SwiftUI Property Wrapper
@StateObject
o When you need to create a reference type inside one of your
views and make sure it stays alive for use in that view and
others you share it with
struct QuizView: View {

@StateObject var quizViewModel = QuizViewModel()


………………..

https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-
stateobject-property-wrapper
SwiftUI Property Wrapper
@StateObject
o To share a StateObject in other views, declare the variable
with @ObservedObject wrapper

struct ScoreView: View {


@ObserveObject var quizViewModel: QuizViewModel

var body: some View {


Text("Score: \(quizViewModel.playScore)")
}
}

Important: You should use @StateObject only once per object,


which should be in whichever view is responsible for creating
the object. All other views that share your object should
use @ObservedObject.
SwiftUI Property Wrapper
@ObservedObject
o more complex properties that might be shared with multiple
classes
o External
o Conform to ObservableObject protocol
import SwiftUI

struct QuestionView: View {


@ObservedObject var model = QuestionModel()

var body: some View {


VStack(content: {
HStack(content: {
Text(model.question)
Text("=")
Text(model.answer)
})
………………………..
@ObservedObject could accidentally release the object it was
storing, because it wasn’t designed to be the ultimate source of
truth for the object. This won’t happen with @StateObject, so
SwiftUI Property Wrapper
@Published
o For an observed object to notify views that important data
has changed
o You use this frequently in your data model
import Foundation

class QuestionModel: ObservableObject {


@Published var playCount: UInt32;

@Published var currentQuestionIndex: Int = -1 {


didSet {
self.playCount += 1
}
}
Let’s continue our SwiftUI Apps
1. HelloSwiftUI
2. SwiftUI Quiz
QuizApp – QuizView UI
import SwiftUI // SwiftUI framework

struct MyQuizViewUI: View {


var body: some View {
VStack(content: {
HStack(content: {
Text("Expression")
Text("=")
Text("Solution")
})
Divider().padding(.bottom)

Button(action: {
}) {
Text("Play")
}.padding(.bottom)

VStack(content: {
Button(action: {
}) {
Text("Solve")
}
Divider().padding(.bottom)
Text("Played # time(s).");
})
})
}
QuizApp -- QuizModel
import Foundation // Notice we not importing swiftui anymore

class QuizViewModel: ObservableObject {


// Every time playedCount changes, it calls objectWillChange.send() to publish
@Published var playedCount: UInt32;

@Published private var num1: UInt32? {


didSet {
self.playedCount += 1;
}
}
@Published private var num2: UInt32?
@Published private var played: Bool;
@Published private var showAnswer: Bool;

// Computed variable
var question: String {
get {
if let n1 = self.num1, let n2 = self.num2 {
return "\(n1) + \(n2)"
} else {
return "Expression"
}
}
}
…………………………………
QuizApp -- Model  View

import SwiftUI

struct QuizView: View {

@ObservedObject var quizViewModel = QuizViewModel()

var body: some View {


VStack(content: {
HStack(content: {
Text(quizViewModel.question)
Text("=")
Text(quizViewModel.answer)
})
Divider().padding(.bottom)

Button(action: {
quizViewModel.nextQuestion()
}) {
Text(quizViewModel.playButtonText)
}.padding(.bottom)

…………………………..
QuizApp -- Application Icon
QuizApp -- Application Icon
Questions?
More SwiftUI App
2. Create and Combining Views

You might also like