当前位置:网站首页>Swiftui 2.0 course notes Chapter 4

Swiftui 2.0 course notes Chapter 4

2022-06-23 05:14:00 Alten wood

Course link :https://www.bilibili.com/video/BV1q64y1d7x5?p=4

Course project warehouse :https://github.com/cnatom/MemorizeSwiftUI

enumeration enum

stay enum in , We can use another enum.enum Variables in , The preceding parameters may not specify a label , Like the one below drink label

enum FastFoodMenuItem{
    
    case hamburger(numberOfPatties: Int)
    case fries(size: FryOrderSize)
    case drink(String, ounces: Int)
    case cookie
    
}
enum FryOrderSize{
    
    case large
    case small
}

enum Variable definitions

let menuItem: FastFoodMenuItem = FastFoodMenuItem.hamburger(numberOfPatties: 2)
var otherItem: FastFoodMenuItem = .cookie //  amount to  FastFoodMenuItem.cookie

according to enum type , Execute different statements

var menuItem = FastFoodMenuItem.hamburger(numberOfPatties: 2)
switch menuItem {
    
    case FastFoodMenuItem.hamburger : print("burger")
    case FastFoodMenuItem.fries: print("freis")
    case FastFoodMenuItem.drink: print("drink")
    case FastFoodMenuItem.cookie : print("cookie")
}

Maybe , The compiler knows menuItem Enumerate the types of variables , So we can also write more simply

var menuItem: FastFoodMenuItem = FastFoodMenuItem.hamburger(numberOfPatties: 2)
switch menuItem {
    
    case .hamburger : print("burger")
    case .fries: print("freis")
    case .drink: print("drink")
    case .cookie : print("cookie")
}

Swift Also support default, The following code ,s neither "goodbye" Neither "hello", So we can only execute default The statement in

let s: String = "helloworld"
switch s{
    
    case "goodbye": ...
    case "hello": ...
    default: ...
}

case Multiple statements can be added later , And you don't need to use break keyword

var menuItem: FastFoodMenuItem = FastFoodMenuItem.hamburger(numberOfPatties: 2)
switch menuItem {
    
    case .hamburger : print("burger")
    case .fries: 
  				print("freis")
  				print("yummy")
    case .drink: 
  				print("drink")
    case .cookie : print("cookie")
}

You can also get the value of an item in the enumeration type

let menuItem = FastFoodMenuItem.drink("Coke", Int,ounces: 32)
switch menuItem {
    
    case .hamburger(let numberOfPatties):print("\(numberOfPatties)")
    case .fries(let size):print("\(size)")
    case .drink(let brand, let ounces):print("\(brand) + \(ounces)")
    case .cookie:print("a cookie!")
}

enum You can also add functions to

enum FastFoodMenuItem{
    
    case hamburger(numberOfPatties: Int)
    case fries(size: FryOrderSize)
    case drink(String, Int,ounces: Int)
    case cookie
    func isDrink(number: Int) -> Bool{
    
        switch self {
    
        case .hamburger(let pattyCount): return pattyCount == number
        case .fries, .cookie : return true
        case .drink(_, let ounces): return ounces == 16
        }
    }
}

optional type Optional

Swift Optional for (Optional) type , Used to handle missing values . Its essence is an enumeration type

enum Optional<T>{
    
		case none
  	case some(T)
}

//  The following groups of statements are equivalent 
var hello: String?
var hello: Optional<String> = .none

var hello: String? = "hello"
var hello: Optional<String> = .some("hello")

var hello: String? = nil
var hello: Optional<String> = .none

Add an exclamation point after the variable (hello!), Meaning for Compulsory unpacking , This method is usually not advisable .

enum Optional<T>{
    
		case none
  	case some(T)
}
let hello: String? = ...

//  Compulsory unpacking , And below switch The basic equal 
print(hello!) // If the variable is empty , Throws an error 

switch hello{
    
  	case .none: //  Throw an error 
  	case .some(let data): print(data)
}

Generally, conditional statements are used to determine whether a variable is empty .

let hello: String? = ...

//  The usual way of writing ( Equivalent to... Below switch)
if let safehello = hello{
    
  	print(safehello)
} else {
    
  	// do something else
}

switch hello{
    
  	case .none: {
    
      	// do something else
    }
  	case .some(let data): print(data)
}

?? Operator can be set for a variable " Optional default "

let x: String? =  ...
let y = x ?? "foo"  //  If x It's empty , be y="foo"

// The above statement is the same as the following 
switch x{
    
  	case .none: y = "foo"
  	case .some(let data): y = data
}

Using a single ? It can judge the null of multiple variables and take values (Optional chaining)

let x: String? = ...
let y = x?.foo()?.bar?.z  // y Equal to the value corresponding to the first non empty variable from left to right 
// If all values are empty , be y Also empty 


Updated MVVM example

Model

//
// MemoryGame.swift
// Memorize
//
// Created by atom on 2022/5/21.
//
import Foundation

//Model
//where CardContend: Equatable  bring CardContent You can use ==
struct MemoryGame<CardContend> where CardContend: Equatable{
    
    
    //private(set)  Read only 
    private(set) var cards: Array<Card>
    private var indexOfFaceUp: Int?  //  Front up card index 
    
    init(numberOfPairsOfCards: Int,createCardContent: (Int) -> CardContend){
    
        cards = Array<Card>()
        for pairIndex in 0..<numberOfPairsOfCards{
    
            let content = createCardContent(pairIndex)
            cards.append(Card(content: content, id: pairIndex*2))
            cards.append(Card(content: content, id: pairIndex*2+1))
        }
    }
    
    // mutating Enable this function to change struct The variable of 
    mutating func choose(_ card: Card){
    
        // Get the... Of the selected card Index, Make sure the card is facing up ( To prevent repeated clicks , This causes the card to keep turning ), Make sure the card is not matched 
        if let chosenIndex = cards.firstIndex(where: {
    $0.id == card.id}),
            cards[chosenIndex].isFaceUp==false,
            cards[chosenIndex].isMatched==false
        {
    
            if let potentialMatchIndex = indexOfFaceUp {
    
                //  If the second open card 
                if cards[chosenIndex].content == cards[potentialMatchIndex].content{
    
                    //  It is the same as the first opened card , Then the two match successfully 
                    cards[chosenIndex].isMatched = true
                    cards[potentialMatchIndex].isMatched = true
                }
                //  After matching successfully , There is currently no card facing up 
                indexOfFaceUp = nil
            }else{
    
                //  If it is the first card opened , Then the cards that have been turned to the front should be turned to the back 
                for index in cards.indices {
    
                    cards[index].isFaceUp = false
                }
                indexOfFaceUp = chosenIndex
                
            }
            cards[chosenIndex].isFaceUp.toggle() //  Turn the card upside down ,toggle It's equivalent to taking the opposite  a = !a
        }
        
    }
//  obtain card The first index of , This function is similar to the built-in function cards.firstIndex(where:{}) The effect is equal to 
// func index(of card:Card)->Int?{
    
// for index in 0..<cards.count{
    
// if(cards[index].id==card.id){
    
// return index
// }
// }
// return nil //  because Int?, So here we can return a nil
// }

    
    //MemoryGame<CardContent>.Card
    //Identifiable: Make every one Card unique , Can be Foreach Unique identification 
    struct Card: Identifiable{
    
        var isFaceUp: Bool = false
        var isMatched: Bool = false
        var content : CardContend
        var id: Int
    }
}


ViewModel

import SwiftUI

//ViewModel
//ObservableObject  bring  @Published  When the decorated variable changes , Will send UI Refresh announcement 
class EmojiMemoryGame: ObservableObject{
    
    //static The initialization order of type variables is in normal var Before 
    // therefore static Class members of can be used as default values for other class members 
    // Such as  var a = EmojiMemoryGame.emojis[1]
    static var emojis = ["","🦴","","","","","","","","",
                         "","","","","","","","","🥩",""]
    
    // Create a Model
    static func createMemoryGame() -> MemoryGame<String> {
    
        return MemoryGame<String>(numberOfPairsOfCards: 3, createCardContent: {
    
            //  In the definition :createCardContent: (Int) -> CardContend //CardContend It's a generic 
            //  therefore , The type is automatically recognized here , take 
            // index in  Identified as  (index: Int) -> String in
            index in
            return EmojiMemoryGame.emojis[index]
        } )
    }
    
    // @Published bring model Every time it changes , Will send UI Refresh announcement  objectWillChange.send()
    @Published private var model: MemoryGame<String> = createMemoryGame()
    
    
    var cards: Array<MemoryGame<String>.Card>{
    
        return model.cards
    }
    
    // MARK: - Intent(s)
    //  towards Model Send from View Received instructions 
    func choose(_ card: MemoryGame<String>.Card){
    
        //objectWillChange.send()
        model.choose(card)
    }
}

View

import SwiftUI

struct ContentView: View {
    
    // @ObservedObject send View track viewModel And refresh UI
    @ObservedObject var viewModel: EmojiMemoryGame

    var body: some View {
    
        ScrollView {
    
            LazyVGrid(columns:[GridItem(.adaptive(minimum: 65))]){
    
                ForEach(viewModel.cards){
     card in
                    MyCardView(card: card)
                        .aspectRatio(2/3,contentMode: .fit)
                        .onTapGesture {
    
                            // View towards ViewModel Send changes Model The notice of 
                            viewModel.choose(card)
                        }
                }
            }
        }
        .foregroundColor(.blue)
        .padding()
        
    }
    
}
struct MyCardView: View{
    
    let card: MemoryGame<String>.Card
    
    var body: some View{
    
        ZStack{
    
            let shape = RoundedRectangle(cornerRadius: 20)
            if card.isFaceUp{
    
                //  On the face 
                shape.fill().foregroundColor(.white)
                shape.strokeBorder(lineWidth: 3)
                Text(card.content).font(.largeTitle)
            }else if card.isMatched{
    
                //  Successfully matched cards 
                shape.opacity(0)
            }else{
    
                //  Facing up on the opposite side 
                shape.fill()
            }
        }
    }
}

// Xcode preview UI
struct ContentView_Previews: PreviewProvider {
    
    static var previews: some View {
    
        let game = EmojiMemoryGame()
        ContentView(viewModel: game).preferredColorScheme(.light)
        ContentView(viewModel: game).preferredColorScheme(.dark)
    }
}
原网站

版权声明
本文为[Alten wood]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/174/202206230155504883.html