WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

2021.4.6 I will finish the project three.

Forums > 100 Days of SwiftUI

Thanks all the source of Swift, the team,that give me a lot of improvements.

1      

This is challenge three of project three.

struct flagImage:View{ var a:String var body:some View{ Image(a) .renderingMode(.original) .shadow(color:.purple,radius:50) .overlay(Rectangle().stroke(Color.black,lineWidth:2)) .clipShape(RoundedRectangle(cornerRadius: /@START_MENU_TOKEN@/25.0/@END_MENU_TOKEN@/))

}

} //call the struct flagImage(a: // the name of the image)

I finished the project three. Thanks,again.

1      

I design a game of rock,scissor,and paper,however,it differs with the requirement of Paul's,but I think it is my first design authentically,so I share with everybody. May it is not so good,I love it at least,that's enough.

import SwiftUI

struct ContentView: View { //2.make an array of String,and we need it refreshes after end every time. @State var gamechoice=["✊","✂️","👋"].shuffled() //3.产生一个随机数 @State var number = Int.random(in:0...2) @State var click1=true @State var click2=true @State var click3=true //4.刷新数组和序号 func gameagain(){ gamechoice.shuffle() number=Int.random(in:0...2) } func result1()->String{ if gamechoice[number]=="✊"{ return "👋"

    }else if gamechoice[number]=="✂️"{
        return "✊"
}else {
           return  "✂️"
        }

}
func result2()->String{
    if gamechoice[number]=="✊"{
        return "✂️"

    }else if gamechoice[number]=="✂️"{
        return "👋"
}else {
           return  "✊"
        }

}
func same(){
    if click1==true{
        click2=true
        click3=true
    }
}
var body: some View {
   //1.place three Text,one for computer,one for winner,the last one for loser.
    VStack{
        Button(action:{
            click1.toggle()
            same()
            gameagain()
        }){
            Text(click1 ? "电脑":gamechoice[number])
                .usemyview()
        }

        Section{
                HStack(spacing:85){
                    Button(action:{
                        click2.toggle()
                       // gameagain()
                    }){
                        Text(click2 ? "winner":result1())

                            .usemyview()
                }

                Button(action:{
                    click3.toggle()
                }){
                    Text(click3 ? "loser":result2())
                        .usemyview()
                }
            }
        }
    }
}

}

struct myview:ViewModifier{ func body(content: Content) -> some View { content .font(.title) .frame(width: 80, height: 30, alignment: /@START_MENU_TOKEN@/.center/@END_MENU_TOKEN@/) .padding() .foregroundColor(.black) .background(Color.green) .clipShape(RoundedRectangle(cornerRadius:20)) } } extension View{ func usemyview()->some View{ self.modifier(myview()) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

1      

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

Sponsor Hacking with Swift and reach the world's largest Swift community!

I have finished the project four,but I need to conclude it,for the reason that Core ML(Machine Learning) is very difficult. Actually,I think that most of us need review what we have learned frequently,I always forget how to use some modifier,how to create a view,and how to write the syntax of the nil coalescing so on. I will continue studying,only persist can we become a real ios developer.

1      

I have finished the project five,but I still need to do it's chapter of wrapup and challenge. In the process,I gain one person's help,thank you again. And the next days,I will go on! My first goal is that I want to buy a MacBook(Pro is fine) with the first salary as an ios developer! Thanks everyone here!

1      

Recent days,my study state is not as good as last weeks,I am trying to adjust myself to accept some failures from study and life that has a negative effect on me. Today,I will finish project 6! Go!

1      

I have finished the project 6,however,I have also forgot it entirely. There are too many new things that I need to learn,too much knowledge that I need to review. Great haste is not always good speed. So I will devote my energy,time into it.

1      

I have finished the Consolidation project 4 to project 6 day. I met a lot of problems,so I listed them here.I just believe I could solve them one day in the future as I presist learning.

Problems: First-----I don't know how to create a Question struct with SwiftUI. Second-------I don't know how to split up views,I put all my views in the ContentView. Third--------I don't understand the requirements of the project throughly,just is it a multiplication tables? If it is,why does it contain 1-12 rather than 1-9?

Here is my code:

// // ContentView.swift // Edutainment // // Created by 林锋 on 2021/4/17. //

import SwiftUI

struct ContentView: View { @State private var num=0 @State private var selectnum="" @State private var answernum="" @State private var numarray=[1,2,3,4,5,6,7,8,9,10,11,12] @State private var questionnumber=["5","10","20","All"] @State private var myselect=Int.random(in: 0...11)

@State private var alertTitle=""
@State private var alertMessage=""
@State private var alertShown=false

@State private var qseries=0
@State private var qelement1=0
@State private var qelement2=0

@State private var iseries=0
@State private var jseries=0

func multiply(){
    //1.几的乘法
    let Intselectnumber=Int(selectnum) ?? 0
    if Intselectnumber<0 || Intselectnumber>12{
        return
    }
    //2.几个问题
    let Intnum=Int(questionnumber[num]) ?? 12
    //3.出问题
    if Intnum != 12{
         if qseries<Intnum{
        qelement1=Intselectnumber
        qelement2=numarray[myselect]
         }else{
            alertTitle="本次回答结束"
            alertMessage=""
             return
         }
    }else{
        if jseries<12{
            qelement2=numarray[jseries]
        }else{
            iseries+=1
            jseries=0
            qelement2=numarray[jseries]
        }
        qelement1=numarray[iseries]
        jseries+=1

    }
    myselect=Int.random(in: 0...11)
    qseries+=1

}
func checkanswer(){
    let Intanswernumber=Int(answernum) ?? 0
    let correctanswer=qelement1*qelement2
    if correctanswer==Intanswernumber{

        alertTitle="您的回答:"
        alertMessage="正确"

    }
    else{
        alertTitle="您的回答:"
        alertMessage="错误"
    }
    alertShown=true
}
func gameagain(){
    qseries=0
    answernum=""
    selectnum=""
}
var body: some View {
    NavigationView {
       VStack{
            Section{
                TextField("你可以选择1-12以内的乘法",text:$selectnum,onCommit:{multiply()
                })
                                    .padding(26)
                                    .font(.title2)
                                    .foregroundColor(.black)
                                    .keyboardType(.numberPad)
                    }
            Form{
                  Section{
                           Picker("你想挑战几个问题?",selection:$num){
                            ForEach(0..<questionnumber.count){
                             Text("\(questionnumber[$0])")
                                  }
                           }
                                .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)

                        }
                Section{
                    VStack{
                        Text("第\(qseries)个问题")
                    }
                    Text("What is \(qelement1)*\(qelement2)?")  .padding()
                        .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)
                }

                    }    
        TextField("请输入你的答案:",text:$answernum,onCommit:{checkanswer()
                    multiply()})
        .font(.largeTitle).foregroundColor(.black)
        HStack( alignment:.center,spacing:80){
            VStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 50) {
                Button(action:{answernum+="1"}) {
                Text("1").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="2"}) {
                    Text("2").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="3"}) {
                    Text("3").foregroundColor(.black).font(.largeTitle)
                }
            }
            VStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 50){
                Button(action: {answernum+="4"}) {
                    Text("4").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="5"}) {
                    Text("5").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="6"}) {
                    Text("6").foregroundColor(.black).font(.largeTitle)
                }

            }
            VStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 50){
                Button(action: {answernum+="7"}) {
                    Text("7").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="8"}) {
                    Text("8").foregroundColor(.black).font(.largeTitle)
                }
                Button(action: {answernum+="9"}) {
                    Text("9").foregroundColor(.black).font(.largeTitle)
                }
            }

        }
        Spacer(minLength: 30.0)

        Button(action: {answernum+="0"}) {
            Text("0").foregroundColor(.black).font(.largeTitle)
        }
            }
       .alert(isPresented: $alertShown){

        Alert(title: Text(alertTitle), message: Text(alertMessage), dismissButton: .default(Text("cotinue")))

       }
       .animation(.default)
         .navigationTitle("Edutainment")
       .navigationBarItems(trailing: Button(action:gameagain){Text("重新开始")})

}

}

}

struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

At last,whatever lever the project is,I finished it by myself. I will look at other's code for the project to improve my ability,refine the code and go on learning. As Paul said "this is a marathon,not a sprint".It is not important that how much works you finished in one day,instead how long you will insist.

1      

Hello,Everyone,I'm here again.Yes,I have finished project 7,including its three challenges.

Those are my codes that were written by myself,of coures,they are useful.

For the first challenge,it is so easy for me to do,what we need to do is that add some codes we have seen them in the privious chapters:

   func deleteitem(_ address:IndexSet){
                  mycost.items.remove(atOffsets: address)
    }

                                    .onDelete(perform: deleteitem)

Second: I use different colors to describe how much we cost,if it is less than 10,its color is black,between 10 and 100,the color is orange,but more than 100,color is red,it is a signal that you spend too much! if a.pill<10{ Text("(a.pill)") .foregroundColor(.black) }else if a.pill<100{ Text("(a.pill)") .foregroundColor(.orange) }else{ Text("(a.pill)") .foregroundColor(.red)

                                }

third: I encounter one problem for this challenge,when I finished for the first time,I met a bug that when I put a data into cost amount with wrong type, the view won't dismiss any more after I clicked the Button of "完成". Fortunately,I solved it by myself,I 'm so proud of that. I just put the sentence------ "self.hide.wrappedValue.dismiss()

" into the givevalue() method,however,it was in the navigationBarItem at the begining.

@State private var alertTitle=""
@State private var alertMessage=""
@State private var  alertshown=false

 func givevalue(){
    var instance=ExpenseItem(itemname: "", type: "", pill: 0)
    instance.itemname=name
    instance.type=whichtype
    instance.pill=Int(totalcost) ?? 0
    if instance.pill==0{
        alertTitle="输入格式错误:"
        alertMessage="请重新输入数字!"
        alertshown=true
        return
    }
    self.hide.wrappedValue.dismiss()
    addobject.items.append(instance)

}

.navigationBarItems(trailing: Button("完成"){ givevalue() })

        .alert(isPresented:$alertshown){
            Alert(title:Text(alertTitle),message:Text(alertMessage),dismissButton:.default(Text("continue")){
            })

1      

It is a long time for me to upload my study records,because I found a job in last days,it is a big challenge for me to work as side as go on learning,I will stick to it. This morning,I am going to be finishing project 8 day three,come on!

1      

I have finished project 8, however,what I need to do is that to finish its wrap up and challenge. I forgot everthing I have learned,what a pity! I need to do some conclusions that will help me reminder some knowledge. And follwing days,I will have three days for vacation,my goal is to finish project 9,and consolidation of project7 to project 9. When I finish that,I will post my process here.

1      

  1. I have finished three challenges of project 8,all them are finished by myself.

  2. At the beginning I think them are may very difficult,but when I try my best to do it ,I find it is significantly easy and funny.

  3. I will share my three challenges' codes and all the conception that how I do that.

  4. See you tonight,I need to go to a toilet and prepare to go to company.

1      

Hello,guys! I am now going to sharing my codes with you.Of course,if you have any idea,you can comment on this remarks. The first challenge is that we need to show the launch date below the mission badge,here is my codes: Text("(mymission.formattedLaunchDate)") to be honest,I don't remember how to write the code of date,it is difficult for me,but I will conclude that.And next post,I will answer the questiion.

The second challenge is we need to show all missions that the astronaut had partipated:

1.I create a constant named allmissions,it's type is array of mission.It will storey all our missions.

let allmissions:[mission]

2.here,I wirte two ForEach(),the first one aims to go through all the missions in our array,and the second aims to go through the crew of per mission,we can find the name of crew in the second ForEach(),so we can judge if the name of crew equals to the id of astronaut,if it is true,we just print the mission.

     ForEach(0..<allmissions.count){num1 in
                ForEach(0..<allmissions[num1].crew.count){
                    if allmissions[num1].crew[$0].name==thisastronaut.id{
                        Text("他参加了以下计划:\(allmissions[num1].displayName),时间是:\(allmissions[num1].formattedLaunchDate)")
                            .font(.title2)
                            .padding(20)

                    }

                }
            }

            struct SwiftUIView_Previews: PreviewProvider {

static let astronauts:[Astronaut]=Bundle.main.mydecode("astronauts.json") static let missions:[mission]=Bundle.main.mydecode("missions.json") static var previews: some View { SwiftUIView(thisastronaut:astronauts[0],allmissions: missions) } }

NavigationLink(destination: SwiftUIView(thisastronaut: who.crewastronaut,allmissions:missions))

3.the last one is that make a button to change the things that be shown:

when I first write the code,I make a button,and the content of text view will be choosed between date and time,but I find that if I tap one item,the other items will also be changed.That seems bad,so I take a long time to solve the problem,of course,I made it.

Button(action:{ show.toggle() show2=num

                    }){
                        Text(show2==num&&show ?"\(missions[num].displayName)":"\(missions[num].formattedLaunchDate)")
                    }

I created two properties,show and show2. the show property aims to change the contents,the show2 aims to decide which one will be changed. I give the num to show2,when you tap the item.

1      

Sorry,I just played games for three days,it is so funny. Go! I will post all my study here,whatever I did.

1      

I learned a few,oh my god,I have too many things.But,I will persist to study! Go !

1      

I have finished project 9.

What I need to do is that finish the challenge and wrap up.

And I will take this week to conclude from project 7 to project 9.

Next monday,I will begin to study project 10.

I swear I will finish all these projects,and find a job as a junior ios developer.

1      

I have finished reviewing and concluding part one and two of project 9.

Tomorrow,I will finish to conclude all of project 9.

And I will upload my process everyday.

1      

Here is my answer for three challenges of project 9! Share with you ! Hopefullly,I look forward to your reply.

// // ContentView.swift // challenge9.3 // // Created by 林锋 on 2021/5/21. //

import SwiftUI

struct ContentView: View { @State private var myamount=0.5 @State private var mynum=100.0

@State private var locate0=true
@State private var locate1=true

var body: some View {
    VStack{
        ZStack{
            colorcyclerectangle(amount: myamount, num: Int(mynum),location0: locate0,location1: locate1)
                .frame(width: 300, height: 300, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
            Button(action: {
                locate1.toggle()
                locate0.toggle()

            }){
                Text("")
                    .frame(width: 300, height: 300, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)

            }

        }
        Text("\(myamount,specifier: "%2.f")")
        Slider(value: $myamount)

        Text("\(mynum,specifier: "%g")")
        Slider(value: $mynum,in:100...200,step:1)

    }
            }

} struct colorcyclerectangle:View{ var amount=0.0 var num=100

public var location0=true
public var location1=true

func mycolor(_ a:Int,_ brightness:Int)->Color{

    var endhue=Double(a)/Double(num)+amount

    if endhue>1{
        endhue-=1
    }
    return Color(hue:endhue,saturation: 1,brightness: Double(brightness))

}
var body: some View{
    ZStack{
        ForEach(0..<num){value in
            Rectangle()
                .inset(by: CGFloat(value))
               // .strokeBorder(mycolor(value, 1),lineWidth:2)
                .strokeBorder(LinearGradient(gradient: Gradient(colors: [mycolor(value, 1),mycolor(value, Int(0.5))]), startPoint: location0 ? .leading:.bottom, endPoint:location1 ?  .trailing:.top))

        }
       // .drawingGroup()
    }
}

} struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

This is the third challenge.

The following code is the first and second.

// // ContentView.swift // Challenge9 // // Created by 林锋 on 2021/5/20. //

import SwiftUI

struct ContentView: View {

@State private var amount=100.0
@State private var linewidth=20
var body: some View {
    VStack{

        arrow(myamount: CGFloat(amount))

            .stroke(Color(hue:0.0,saturation: 1,brightness: 1),style:StrokeStyle(lineWidth: CGFloat(linewidth),lineCap: .round,lineJoin: .round))
         .frame(width: 300, height: 300, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)

            .onTapGesture {
                withAnimation(){
                    self.linewidth=Int(CGFloat.random(in: 3...50))
                }
            }
        Slider(value:$amount,in:100...200,step:1)

    }

}

}

struct arrow:Shape{

var myamount:CGFloat

func path(in rect: CGRect) -> Path {
    var newpath=Path()

    newpath.move(to: CGPoint(x: rect.midX, y: rect.minY))

    newpath.addLine(to: CGPoint(x: myamount, y: myamount))
    newpath.addLine(to: CGPoint(x: rect.width-myamount, y: myamount))
    newpath.addLine(to: CGPoint(x: rect.midX, y: rect.minY))

    newpath.move(to: CGPoint(x: rect.midX, y: myamount))

    newpath.addLine(to:CGPoint(x: rect.midX, y: rect.maxY))

    return newpath
}

} struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

1      

I finished the challenge of the conclusionof from project 7 to project 9.

Generaly speakinng, it is significantly easy.Beacause all the functions we bulit that we can refer to project 7----IExpense.

I hope you guys also feel good for it.

Of course,I met one problem,it is hard to explain clearly with some sentences,so I will contiue to solve it by myself.

One new api I learned is Timer() modifier.

Tommorow,I should begin to learn Project 10.

1      

Project 10

hello,guys,I am so please to see you here again! And I have a lot of things to share with you.May be three!

The first thing I want tell you is that I have finished the challenges of project 10,of course,I have learned a ton of things.To be honest,I am now more interesting in Swift and SwiftUI through the learning of this project,it shows me many things such as what the URL is,how to encode and decode @Published properties,how to check the network resort of the third party manager,etc.

the first challenge:how do we ensure whether a string is valid when it is whitespace? we should write a extension for String like this: extension String{ var isspace:Bool{ return allSatisfy({$0.isWhitespace}) } }

When a parameter is type of String with all whitespace, we use parameter.isspace to judge,if it is whitespace,the value is true.

the second challenge:how do we check the status of our phones' network?Here,we should leverage the third dependency manager:Reachability! let reachability = try! Reachability() reachability.whenReachable = { reachability in if reachability.connection == .wifi { print("Reachable via WiFi") } else { print("Reachable via Cellular") } } reachability.whenUnreachable = { _ in messagetitle=""//a alertmessage bulit by myself messagecofirm="请打开WI-FI或者数据"// as same as messagetitle showing=true//as same as messagetitle return } do { try reachability.startNotifier() } catch { print("Unable to start notifier") } reachability.stopNotifier()//when you don't want the notifier,you can stop it by this syntax.

I really have a deeper comprehension for Swift is more like a kind of natural language by through this dependency manager,and this is also the reason why I don't provide any annotations for the code that it is so clear to be read and understood. And the biggest problem of the process of using it is how to import it,I had took much time to solve the problem.Image is better than text,please look at the following pictures: Firstly,drag the Reachability project into your aimmed project: Secondly,add Reachability.framework to the setting. Last,you should write "import Reachability" before you use it. Unfortunately,I can't introduce image,sorry.But you can search it online.

the last one: the conbination of struct and class with @Published,I want to say that this actually is a simple test for you,me and everyone. struct choice:Codable{ static let alltypes=["西瓜","草莓","芒果","🍊","🍌"] var type=0 var number=[1,1,1,1,1] var sepcialrequest=false var extrafrosting=false var extrasprinkles=false } final class menu:ObservableObject,Codable{ enum Codingkeys:CodingKey{ case mychoice } @Published var mychoice=choice() func encode(to encoder: Encoder) throws { var container=encoder.container(keyedBy: Codingkeys.self) try container.encode(mychoice, forKey: .mychoice) } init(){} init(from decoder:Decoder)throws{ let container=try decoder.container(keyedBy: Codingkeys.self) mychoice=try container.decode(choice.self, forKey: .mychoice) } } there is no more things so just look at those codes.

I don't know whether you have noticed that there is a bug in our porject 10,however,it isn't the false of codes but the design.If you think about it more,you will find when we order different cupcakes it can't be achieved,you have to order the same type cupcakes. So I rebuild it like this:

  static let alltypes=["西瓜","草莓","芒果","🍊","🍌"]
    var type=0
 var number=[1,1,1,1,1]
  NavigationView{
            Form{

      Group{
    ForEach(0..<choice.alltypes.count,id:\.self){drink in
        Stepper(value:$whatIchoose.mychoice.number[drink],in:1...20,step:1){
            Text("\(choice.alltypes[drink])")
            Text("\(whatIchoose.mychoice.number[drink])杯")
            }
    }
  }

At last,I want to tell myself that remember to review ,conclude and go on!

1      

Project 11.

Yeap,I am always here.Those days I find that I can grasp the tutorials more and more easier than before.Concerned my speed is increasingly fast,I decide to stop to review project 10 and 11 for the reason that there must be lots of things are worthy me reviewing.

Ok,here are three challenges as usual I share them with you :

First,fix the bug that there is no picture when we don't make choice.But I want to explain why it appears in our project though there is no wrong in our codes.At beginning,we set the default value of genre as "",however,the default value of rating is "3",so you can see that even you make no choice on rating,it has a default choice that is three.Does genre has a default choice? yes,"" is its choice,wheares we don't have a picture that named "",so there is nothing.

About solutions,we have two ways: 1.change the default value of genre to any kind of names in our array,such as :Kids,Rommance.

     @State var  genre="Fantasy"//如果不给值 想选第一个的话 你要滑动到其他的再回到第一个。 或者 勾选第一个

''' 2.As we all know,the value of book.genre is an optional value though it is different with Swift's optional value, we can provide it with a value as default when we try to unwrap it.

   Image(detailbook.genre ?? "picturename") //your picture name.

Second,modify the book.title as red color when its rating is under one star.We can use a condition like this:

  Text("书名:\(num.title!)")
                        .font(.headline)
                        .foregroundColor(num.rating<2 ? .red:.black)

last,add date for our books. 1.add attribute. 2.add a datePicker,then give the value to book.date property. 3.show it with a custom format like in Moonshoot project.

      func time(_ dates:Date)->String{
    let dateformatter=DateFormatter()
        dateformatter.dateFormat="MM/y"
        return dateformatter.string(from: dates)
}

 Text("作者:\(num.author ?? "")")
                            Text("\(time(num.date!))")

                        }

                        DatePicker("出版日期", selection: $date,displayedComponents:.date)

Actually,the third one is not perfect,I feel no comfort for it,I wish I can modify it in the following oneday.``

1      

Project 12

Ok,congratulate to myself for I have finished project12.My god,I feel it has many things we need to learn,though the grade of its difficulty is medium,so I want to conclude and share with you.

I want to begin with its three challenges:

Here are my codes:

import SwiftUI

struct filterchoice: View {
    var myrequest:FetchRequest<Teacher>
    @Environment(\.managedObjectContext) var moc

    enum predicate{
        case BEGINSWITH
        case CONTAINS
    }

        init(_ array0:[NSSortDescriptor],_ p0:String){
            self.myrequest=FetchRequest<Teacher>(entity: Teacher.entity(), sortDescriptors: array0,predicate: NSPredicate(format: "age \(predicate.BEGINSWITH) %@", p0))
    }
    func deleteitem(at offsets:IndexSet){
        for offset in offsets{
            let item=myrequest.wrappedValue[offset]
            moc.delete(item)
        }
       try? self.moc.save()
    }
    var body: some View {
        List{
            ForEach(myrequest.wrappedValue,id:\.self){num in
                Section(header: Text(num.truename)){
                    Text("性别:\(num.truegender),年龄:\(num.age)")
                }

            }
            .onDelete(perform: deleteitem)
        }
    }
}

It works well except one problem. As you can see,we have two parameters in "init(){}",one is an array of NSSortDescriptor,another is string of "Predicate".In the ContentView

import SwiftUI
import CoreData

struct ContentView: View {

    @Environment(\.managedObjectContext) var moc
    func add(){
        let teacher0=Teacher(context: self.moc)
        teacher0.name="天一"
        teacher0.age=123
        teacher0.gender="男"

        let teacher1=Teacher(context: self.moc)
        teacher1.name="天"
        teacher1.age=456
        teacher1.gender="女"

        let teacher2=Teacher(context: self.moc)
        teacher2.name="狗蛋"
        teacher2.age=678
        teacher2.gender="男"

        let teacher3=Teacher(context: self.moc)
        teacher3.name="猪狗"
        teacher3.age=48
        teacher3.gender="女"
        if self.moc.hasChanges{
            try? self.moc.save()
        }

    }
 @State private var value=4

    var body: some View {
        VStack{

            filterchoice( [NSSortDescriptor(keyPath:\Teacher.age, ascending: true)], "\(value)")

  //         filterchoice([NSSortDescriptor(keyPath:\Teacher.age, ascending: true)])

//I find that if I use the parameter ----predicate,I cannot click add button to add something,the program will clash.
            Button(action:{
                add()
            }){
                Image(systemName:"plus")
            }
                Button(action: {
                    if value==4{
                        value=6
                    }else{
                        value=4
                    }
                }){
                    Text("change")
                }

        }
    }

I need your help. Thanks.

  1. filterchoice( [NSSortDescriptor(keyPath:\Teacher.age, ascending: true)], "(value)")

  2. filterchoice([NSSortDescriptor(keyPath:\Teacher.age, ascending: true)])

If I use syntax of number 1,when I run the app,if I click add button then app crashed.Here are reporting information:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't do a substring operation with something that isn't a string (lhs = 123 rhs = 6)' terminating with uncaught exception of type NSException

if I use syntax of number 2,of course,I modify the "init(){}" to the right way,everything works well.So I have to use syntax of number 2 to add some data for test,after that I replce it with syntax of number 1,of course,what I still cannot do is click the add button.

1      

Milestone 10 to 12.

Remember to create the names of transformer and custom class by yourself.For example,as shown in the following picture:

Even I look at the tutorial,I can't send a picture off the website.Who can tell me how to send a local image to the website???????

1      

Project 13.

First,I finished a new project again,there are lots of new things we need to learn in the project for me a jackroo of UIKit.I want to summary it simply what I still remember now. (1)What are differences among @State,@Binding,and Binding<T> ? I say that when we use parameter in different views,we should use @Binding, instead we use @State and Binding<T> when properties are in the same view,like ContentView.Of course,they have many differences in essence. (2)actionsheet is almostly as same as sheet and alert.It slides up from the bottom of the screen,and includes title,message,and an array of buttons,such as cancel(),default(),destructive(). (3)UIImagePickerController,this is a new thing for me,however,as soon as we can hold the logical core,it won't be a big challenge for us. (4)Different filters in CoreImage.What we need to remember deeply is that the relationship among User's Image,swiftUI image,UIImage,CIImage and CGImage.One of the most important thing is we'd best to create context only one,because it is expensive. (5)Coordinator and delegate. (6)UIImageWriteToSavedPhotoLibrary. (7)How to change filter dynamically? (8)How to check inputkeys of one filter?

OK,the next is my codes to three challenges,and there is no difficulty:

---If there is no picture in the gray rectangle when we click the save button,there should be post an error.Actually,the best way is to show an alert.But here,I plan to print something like this:

  func wirtetoalbum(image:UIImage?){
            if image == nil{
                print("没有可保存的图片")
                return
            }

            UIImageWriteToSavedPhotosAlbum(image!, self, #selector(saveError), nil)
        }

yes,I change the type of image to UIImage?, and make sure it is not nil before we go on the program.

-----make the button that we can choose different filter when we click it show the name of the current filter we are using.It just we create a @State string property,and give the filters'names to it.

  @State private var title="changefilter"

  Button(action:{actionsheetshow.toggle()}){Text(title)
                        .frame(maxWidth:.infinity)
                    }

  .default(Text("sepia"), action: {
                        self.setfilter(CIFilter.sepiaTone())
                        title="sepia"
                    })   //the rest of filters should be like this

-------add a slider,use it to control our radius input keys.


   let myradius = Binding<Float>(
            get:{
                self.radius
            },
            set:{
                radius=$0
                changeimage()
            }
        )
                  Slider(value: myradius,in:10...100)
                  //  .disabled(isclick)
                Text("半径:\(radius,specifier:"%.2f")")

     if myfilter.inputKeys.contains(kCIInputRadiusKey) { myfilter.setValue(radius, forKey: kCIInputRadiusKey) }

That is all,I wanna say remember to make sure if a picture has been shown before we change and ,save it.

1      

Project 14.

Yep,I finished this project by tooking much time and energy,I just wanna say it is the hardest project we have met so far.There are many things are unfamiliar to us,like MKPointAnnotation,MKAnnotation,MapView,they confused me a lot.I found,however if you can look at it repeatly you will find you gradually grasp all of them,maybe not as difficult as begin.

Ok,let me have a review and conclude for some problems that I met in my learning progress.

Have you get the hang of thoes skills?

(1)Override operator.This is may familiar to you if you had learned C++,there is a difference that the methond name called "<" less than,if we wanna get an array with ascending sequence,we don't have an equivalent called “>”in swift,we need to filp the return of the less than method,or change the closure.Do you still remember "="? What is its overriding form?

(2)Write to your document directory.This is very clearly,firstly we need find the path;second,adding a file name to the url;third,we should use some method to finish it,futhermore,the encoding of data is very important.

(3)Face id and Touch id.This is a action relates to user's privacy,so we should take it seriously.It has some following steps: import LocalAuthentication, add"Privacy-user FaceId description" in Info.plist,its function to explain to user why we want to use Face id or Touch id,of course,this statement is for Face id specially. Last,with some method we can achieve it,".canEvaluatePolicy",".evaluatePolicy",you should remember you can't put the first method in the second that will caues deadblock. On,one more important,we define a varitety named error,the type of it is "NSError?",I guess it is very weird to you,it is Objective-C object,and when you use it remember to add "&" before it.It is almost as same as a operator that gets one's address in C++.

(4)MapView.When we wanna import an empty map in our app,we should create a struct conforms to the "UIViewRepresentable" protocol.What I wanna to intense is when you use code completion in Xcode12 and Swift 5.0,you should find this---

//    func makeUIView(context: Context) -> some UIView {
//        <#code#>
//    }
//    func updateUIView(_ uiView: UIViewType, context: Context) {
//        <#code#>
//    }

you should change "some UIView" "UIViewType" to "MKMapView",otherwise you can't use ".annotation" because they don't have a member of "annotation".

(5)Coordinator.In different context it has different type,like project 13 and 14,it conforms to different protocol,but the concept is similar that acts as the delegate of UIView.

(6)MKPointAnnotation.It conforms to MKAnnotation,we can create a instance of it,which has many properties,such as title,subtitle,coordinate.Besides,we can use MKPinAnnotaionView() to customize our view.

Ok,I have a heck of a lot of things to write here,but I decide to talk with myself.So,here is the three challenges:

(1)What is the difference when we give all the modifiers to Image or give them to the Button? There is actually no distinguish on the appearance,but the function changes a lot.When those modifiers belong to Image,we can tap everywhere of the circle button,insteadly we must click precisely on the "+" symbol then it can work when those modifiers belong to Button.

(2)Rewrite Mapview,Circle,Button.When you finish it,your codes should like this:

  ZStack{
      if islocked{
      mymap(place: locationarrary, centerlocation: $instantialcoordinate, dettailshow: $detailshow, wherechoose: $wherechoose)
          .edgesIgnoringSafeArea(.all)
      centercircle()
      PinButton(content: $content, content2: $content2, instantialcoordinate: $instantialcoordinate, locationarray: $locationarrary, wherechoose: $wherechoose, sheetshow: $sheetshow)
      }else{
          Button(action:{unlock()}){
              ZStack{
              Rectangle()
                  .frame(width: 100, height: 100, alignment: .center)
                  .foregroundColor(.orange)
                  .clipShape(RoundedRectangle(cornerRadius: 20))
                  Text("轻触解锁")
                      .foregroundColor(.black)
                      }
          }
      }
  }

It is more clearly than it was.We just need to pass some parameters into the Button,Circel,Map.

(3)When error occurs during our biometric authentication we should present an alert.The following codes work well:

    @State private var errortitle=""
    @State private var errormessage=""

     func unlock(){
        let myphone=LAContext()
        var error:NSError?
        if myphone.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error){
            let reason="we want to show your data"
            myphone.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason:reason){success,appearerror in
                DispatchQueue.main.async{
                    if success{
                        self.islocked=true
                    }else{
                        self.detailshow=true
                        self.errormessage="请摘掉眼镜口罩帽子!"
                    }
                }
            }
        }else{
            self.detailshow=true
            self.errormessage="未开启人脸识别"
        }
        self.errortitle="错误"

    }
        .alert(isPresented:$detailshow){
            Alert(title: Text("\(wherechoose?.title ?? "\(errortitle)")"), message: Text("\(wherechoose?.title ?? "\(errormessage)")"),primaryButton: .default(Text("OK")){},secondaryButton: .default(Text("edit")){
            sheetshow.toggle()
        })
        }

That is all,I hope I can continue to learn, review again and again.

1      

Project 15

Last days I lost all my data on my disk on the reason that I remake my computer's system,forgeted to back up.

If I want to follow the process of project 15,I have to rebuild project 2,7,and others,it will take much my time,and my primary task is to finish the swiftUI 100 days,so I just leave it for some days,I will complete it when I begin to review all the projects for the sencond time.

Maybe it will at september.

1      

Milestone project 13 to 15

I spend four days making the challenge,but I don't know how to share my working with you because it contains four subviews.Maybe you can contact with me through my QQ,1092908676.

And I can tell you one thing,if you wanna change our annotation's style when you drop a pin on the map,like an image,here is the method that you should use as same as usual:

 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            let reuseId = "test"
            var anView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
            if anView == nil {
               anView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
                anView?.image=parent.mapimage // the image should be your image
                anView?.frame.size=CGSize(width: 30.0, height: 30.0) // adjust the size of image
                anView?.canShowCallout = true
                anView?.rightCalloutAccessoryView=UIButton(type: .detailDisclosure)
            }else {
                anView?.annotation = annotation
            }
            return anView!
            }

And I met a problem,which looks very simple but is cunning:

struct user{

}

var user1=[user]()
var user2=[user()]()

Can you differ their differences?

Tonight,I will begin to learn project16,of course,as the following days I will review the project 14,at that time will make this challenge to be perfect.

1      

Project 16 !

Hey,guys,I have finished project 16.Again,I come here to share my feeling with you about the whole learning process.As we all know,all the contens of the project are about swiftUI pure,so it is not as hard as other projects,though there are many things we need to remember. I wanna make a simple conclusion and review: (1)@EnvironmentObject,we should send one with".environmentObject(xxx)" firstly,then accept it with "@EnvironmentObject".Attention,if you send one to environment,you must accept it,otherwise,your codes crash.

(2)objectWillChange,it should be used at class's properties.

(3)TabView is the parent view,its priority is older than navigationview.We can add "tabItem","tag" attributes.

(4)Result type.The form of it is really unfamiliar to us,maybe we need to practice more.

(5)ImageInterpolation,its function is it can smooth the image when you scale it up.It has many types,such as ".none",".small",".medium".The first one is we usually use.

(6)context menu,you can use it below any views,".contextMenu{}",in the closure you can add as many buttons as you want.

(7)local notification.First,we should create an instance of UNNotificationCenter.current(),second,add request and post request.Last,remember to ask for permission.

(8)import third party dependencies.I understand the meaning of number of vision,like"11.2.1",11 is major number,2 is minor nuber,1 is patch number.This aslo explain one problem why I fail to update my computer system vision from 10.15.7 to 11..2.1,because major number has been changed,that means some API had been broken.

OK,there are still many things we can learn by observe carefully, but here is enough.And the following codes are for three challenges of this project:

(1)add an icon.I download a software from the internet,it is called SF Symbol.It contains all SF Symbol of Apple,you can use it to search what you want.I choose "people.crop.circle.checkmark","people.crop.circle.exclam",and the color of icon will be changed by wether this perosn has been contacted,between red and green.

  VStack{
                      Image( systemName: num.iscontacted ? "person.crop.circle.badge.checkmark":"person.crop.circle.badge.exclam")
                          .resizable()
                          .scaledToFit()
                          .frame(width:50,height:50)
                          .foregroundColor(num.iscontacted ?.green:.red)
                      }

(2)Use JSON and the documents directory for saving and loading our user data.You should commnent out your codes of "UserDefault" saving before you write some codes,because you will not discover any problems if you make wrong,after all,your original codes work well.Actually,this is easy,what you need to do is make your class be Codable.

class allperson:ObservableObject,Codable{
    static let savekey="save"

        //  @Published private(set) var personarray:[person]
    @Published  var personarray:[person]

    enum CodingKeys:CodingKey{
        case personarray
    }
    func getdirectory()->URL{
        let path=FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return path[0]
    }
    init(){
        let mypath=FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("user.data")
print("shitu zairu")
        if let mydata=try? Data(contentsOf: mypath){
            print("dd")
            if let users=try? JSONDecoder().decode([person].self, from: mydata){
                self.personarray=users
                print("载入成功")
                return
        }
        }
        print("dddddd")
        self.personarray=[]
    }
    required init(from decoder:Decoder)throws{
        let container=try decoder.container(keyedBy: CodingKeys.self)
        personarray=try container.decode([person].self, forKey: .personarray)
    }
    func encode(to encoder: Encoder) throws {
        var container=encoder.container(keyedBy: CodingKeys.self)
        try container.encode(personarray, forKey: .personarray)
    }
//    init(){
//        if let decodedata=UserDefaults.standard.data(forKey: allperson.savekey){
//            if   let mydata=try? JSONDecoder().decode([person].self, from: decodedata){
//            self.personarray=mydata
//                return
//        }
//        }
//        self.personarray=[]
//
//    }
    func change(_ structself:person){
        objectWillChange.send()
        structself.iscontacted.toggle()
        save()
    }
// private   func save(){
//        if let encodedata=try? JSONEncoder().encode(personarray){
//            UserDefaults.standard.set(encodedata, forKey: allperson.savekey)
//        }
//    }
    func add(_ test:person){
        personarray.append(test)
        save()
    }

    func save(){
        let mypath=getdirectory().appendingPathComponent("user.data")

        if let mydata=try? JSONEncoder().encode(self.personarray){
            try? mydata.write(to: mypath)
            print("保存成功")
        }
    }

}

first,you should make the class be codable,because the "personarrary" is "Published",which can't be decoded or encoded,we should write "enum","required init(){}","func encode(){}"by ourselves. second,we should write a new method of saving,with FileManager. third,for the initialization of the class, you should read data from where you save them. last,we should rewirte the property-----personarrary,because it shoul be read and write freely.

(3)Use an action sheet to customize the way users are sorted in each screen – by name or by most recent. I believe that you can write some codes for achieving actionsheet easily,but the sort may take your some time.OK,here is code:

class person:Identifiable,Codable,Comparable{
    var id=UUID()
    var name=""
    var address=""
    var date=Date()
    static var sequence=""
   fileprivate(set) var iscontacted=false
    static func <(lhs:person,rhs:person)->Bool{
        if self.sequence=="date"{
        return lhs.date>rhs.date
        }else{
            print("zaina")
        return lhs.name>rhs.name
    }
    }
    static func == (lhs:person,rhs:person)->Bool{
        if self.sequence=="date"{
        return lhs.date==rhs.date
        }else{
            return lhs.name==rhs.name
    }
    }   
}

This is first step of my work,add "Comparable" protocal,wirte sorted method,but do you noticed what I have added? Yes,"static var sequence="" ",it belongs the calss person rather than an instance of it. And I give it two values "name" and "date",which is our base of sorting. Still,"var date=Date()",with it in place,we can sort with date.Next is actionSheet codes:

 .actionSheet(isPresented:$actionshow){
          ActionSheet(title: Text("排序联系人"), message: Text("如何显示联系人?"), buttons:[
   .default(Text("姓名"), action: {
          person.sequence="name"                                                                                                                                
          self.totalpeople.personarray=self.totalpeople.personarray.sorted()}),
  .default(Text("时间"), action: {
             person.sequence="date"
             self.totalpeople.personarray=self.totalpeople.personarray.sorted()}),
  .cancel()])
      }

I only need to give one value to sequence,which value depends on what we want to rely on to sort.

That is all,I hope I can cotinue to learn,and prepare for my first app.

1      

你不会是87年的人吧?

1      

没有啊 95的

1      

Project 17 !

I am not happy with the completiom of the project,it confused me a lot especially challenge two.To be honest,all those knowledge of this project give me mor thinking,if you wanna build a great,fatalistic and excellent app,you need to take care of many things,but how I should do somehow I am just a jackaroo,all what you need to do is keep your confidence,hold your persistence,go on learning from trival learning.

(1)Gesture.There are several types of gesture,what impressed me are TapGesture,DragGesture,and Sequence.If you have noticed that TapGesture and DragGesture,both of them have onChanged() and on Ended() modifiers,of course,TapGesture still has .scaleEffect(),instead DragGesture has .offset().By using Sequence modifier,we can combine different types of gesture to generate different effection.

(2)UINotificationFeedbackGenerator() comes from UIKit,it is different with CoreHaptics.

(3)allowHitTesting() very likes disable(),do you still remember that? The only difference between them is they will have opposite result with the same value,like true or false.

(4)create a timer, the syntax is this sentence: var mytimer=Timer.publish(every: 1, on: .main, in: .common).autoconnect().We need to grasp what these parameters mean. Besides, I am very curious about one question:stop the timer and recreate it everytime,will that cause a problem of perfomance when we restart the game?

(5)Different styles of NotificationCenter,we send kinds of them,and receive them.such as:UIApplication.willResignActiveNotification,UIApplication. willEnterForegroundNotification.But remember one special thing:VoiceOver is controled by "accessibilityEnabled"

(6)Accessibility.Here are some kinds of common accessibilities,like accessibilityDiffrentiateWithoutColor,accessbilityReduceMotion,accessbilityReduceTransparency.

In the process of implementation of the project,what the biggest harvest is that I totally understand the coordinator of the ios,its center is on the center of the screen,below the middle line the value of y coordinator is growing over the length,on the right of the y coordinator,the value of x is increasing over the direction.So,you should able to master how to calculate the location of every card.

And,the following codes for three challenges:

(1)when the timers runs out,I design the app to show an alert that will congratulate you or noftify you regrettably.Of course,in term of customized haptic,I just use what our teacher had showed us. Unfortunately,though all my code works well, there is one bad thing,I will tell you at last.

@State var shownotify=false
    @State var alerttitle=""
    @State var alertmessage=""
            .onReceive(mytimer){num  in
                if self.time>0&&isshow&&self.cards.count>0{
                          self.time-=1
               }                       
                if self.cards.count==0||self.time==0{
                      if self.cards.count==0{
                        print("YOude")
                          alerttitle="🎉恭喜🎉"
                          alertmessage="完成所有题目,用时\(100-time)秒"
                      }else{
                          if self.time==0{
                                          alerttitle="很遗憾"
                                          alertmessage="规定时间内未完成所有题目!"
                          }
                      }
                    implementhaptic()
                      shownotify=true
                    self.mytimer.upstream.connect().cancel()

            }
                                }
  .alert(isPresented: $shownotify, content: {Alert(title: Text(alerttitle), message: Text(alertmessage), dismissButton: .default(Text("OK")))})

When the time is over or we answered all questions,then the alert will be shown,its contents depends on your result.Oh,I canceled the timer,and recreated it when we restart our game.Will it cause a problem of perfomance as I asked you before?

The use of customized haptic is easy,you can write all codes by referring to what we have been teached,there already has been one for us actually.

(2)setting screen.To be honest,it tooks me much time rather than the code itself, I encountered a problem about the presentation of the alert and the screen when the last card is moved to the left to delete it only at the time.I found that the alert and the setting screen appeared at almost same time,but I can't see the alert because the setting screen is a sheet,it slided up from the bottom of the screen,so it covered the alert.And I don't know how to solve that in present,maybe I can solve it in the future.

in CardView:

 @Binding var wrongshow:Bool
            .onEnded{value2 in
                if abs(self.distance.width)>100 {
                    if self.distance.width<0{
                        self.generator.notificationOccurred(.success)
                            wrongshow=true
                    }
                    self.removal?()
                }else{
                   // withAnimation(.spring()){
                    self.distance = .zero
               // }
                }
            }

in ContentView:

    @State var wrongshow=false
.sheet(isPresented: $wrongshow){
            settings(wrongcard: deletecard, allcard: $cards)
        }

in SettingView:

@State var wrongcard:card
    @Binding var allcard:[card]
    @Environment(\.presentationMode) var wrongshow
    func addwrongcard(){
        allcard.insert(wrongcard, at: allcard.count)
    }
    var body: some View {
        NavigationView{
            VStack{
                Text("确认重新添加到卡列表请点击右上角!")
            }
            .navigationBarItems(leading:Button("cancel"){
                wrongshow.wrappedValue.dismiss()
                     },trailing: Button("add"){
                addwrongcard()
                 wrongshow.wrappedValue.dismiss()
            })
        }
    }

(3)we need to create a modifier to fix the problem of color.Do you remember how to create a custom modifier?I forget that at all.

 //  .fill(distance.width>0 ? Color.green:Color.red))
                      .modifier(myColor(withoutcolor: distance.width>0))
                      )
 struct myColor:ViewModifier{
  var withoutcolor:Bool
  func body(content: Content) ->some View{
      RoundedRectangle(cornerSize: CGSize(width: 40, height: 40),style:.continuous)
          .fill(withoutcolor ? Color.init(red: 0, green: 1, blue: 0):Color.init(red: 1, green: 0, blue: 0))
      //Color(red: 0, green: 1, blue: 0)
  }
}

I think what cause the problem is that the green is not pure green,it is modified by ios for more suitable and moderately for us to see.If I am right,I write a modifier,create a variable,its type is Bool,a roundedrectangle is as same as we built in the project,and change its color of fill to that.It is pure green,actually I don't find there is red in the process of when I move the card to the right with a distance that is not enougt to remove it,then release it,it will back to the original location.

That is all,if I have made some mistakes,please tell you,thank you a lot.

I plan to finish all the course before July,and commence on my first application----CWeather,hopefullly I can finish that.

1      

(1)MagnificationGesture() -----------scaleEffect() (2)RotationGesture()-----------------ratationEffect() (3)DrageGesture()------------------offset()

1      

Project 18!

I just wanna share you with a special effect with GeometryReader.

let colors: [Color] = [.red, .green, .blue, .orange, .pink, .purple, .yellow]
 GeometryReader{full in
            ScrollView(.vertical){
                VStack{
                ForEach(0..<50){num in
                    GeometryReader{geo in
                        Circle()
                            .fill(colors[num%7])
                            .frame(width:100)
                            .rotation3DEffect(
                                .degrees(Double(geo.frame(in: .global).minY-10)),
                                axis: (x: 0.0, y: 1.0, z: 0.0)
                            )
                            .position(x:full.frame(in: .global).midX)

                    }
                    .frame(height:100)
                }
                }
                .background(Color.gray)
            }
        }

Its effect is that in a vertical scrollview there are fifty circles,each one loactes in the middle,when you scroll,they will spin.You can have a try. I used Position() modifier to potion them with absolutely position.

The remained three challenges will be finished in one day of the future,but I promise I will do that.

I will stick to review ,learn and update!

1      

Milestone 16--18

This time I just share my app with you,actually it is very easy.I still need to try to vibrate my phone with another way----CoreHaptics,and show the possible value of the dice everytime we roll it with Dispatch.main.asyncafter().

Tommorrow I will do the remaining things,now, here is my code:

//create a variable for the number of the side of dice
  @State var sidenumber=6
  //create a variable for result to show
  @State var result=0
  //create a status for actionsheet to change the number sides of dice
  @State var isshown=false
  //create a variable for the total rolled number of the dice
  @State var totalnumber:Int16=0
  /*
   make the value rolled by the dice flick through various possible values before settling on the final figure
   */
  //create a timer
  @State var mytimer=Timer.publish(every: 0.5,tolerance: 0.2, on: .main, in: .common).autoconnect()
  //create an initiator
  @State var begin=0
  //create a variable for the number of showing the number of rolling dice every time
  @State var end=5
  @State var click=false
  /*
     use core data to store our data:
         1.the result of we rolling the dice---an array
         2.the number of rolling dice
   */
  //create entity , context,save method,delete method.
  @Environment(\.managedObjectContext) var moc
  @FetchRequest(entity:Dice.entity(), sortDescriptors: [], animation:.easeInOut) var mydice:FetchedResults<Dice>
  func save(){
      let test=Dice(context: moc)
      test.totalnumber=self.totalnumber
      test.result=Int16(self.result)

      if self.moc.hasChanges{
          try? self.moc.save()
      }
  }
  func delete(at offsets:IndexSet){
      for offset in offsets{
          self.moc.delete(mydice[offset])
      }
      if self.moc.hasChanges{
          try? self.moc.save()
      }
  }
  func deleteall(){
      for n in mydice{
          moc.delete(n)
      }
      if self.moc.hasChanges{
          try? self.moc.save()
      }
  }
  //create a random array with any count
  func rolldice()->Int{
      let randomarray=makearray(sidenumber)
      return randomarray.randomElement() ?? 0
  }
  //create a random array with fixed width and qutity
  func makearray(_ n:Int)->[Int]{
      return  (0..<n).map{_ in Int.random(in: 1...n)}
  }
 //create vibration by two ways:UINotification and CoreHaptics
  //first:
  func vibrate(){
      let generator=UINotificationFeedbackGenerator()
      generator.notificationOccurred(.success)
  }
  //second:
  var body: some View {
      //create tapview
       TabView{
           NavigationView{
                 VStack{
                       Text("本次掷骰子: \(totalnumber) 次")
                           .font(.largeTitle)
                       ZStack{
                       Circle()
                           .fill(Color.red)
                       Text("\(result)")
                           .font(.largeTitle)
                   }
                   .frame(width: 100, height: 100, alignment: .center)
               }
               .onTapGesture(perform: {
                       vibrate()
                  self.mytimer=Timer.publish(every: 0.5,tolerance: 0.2, on: .main, in: .common).autoconnect()
                  self.click.toggle()
                       self.totalnumber+=1

                   })
               .navigationTitle("Roll Dice")
               .navigationBarItems(trailing: Button("change"){
                   isshown.toggle()
               })
                 .onReceive(mytimer){time in
                  if click{
                  self.result=rolldice()
                  self.begin+=1
                  if begin>end{
                      self.save()
                      self.mytimer.upstream.connect().cancel()
                      self.begin=0
                      self.click=false
                  }

                  }
                 }
                 }

               .tabItem{
               Text("roll")
               Image(systemName: "star")
               }
          NavigationView{
          List{
              if mydice.count>0{
              ForEach(0..<mydice.count,id:\.self){num in
                  VStack{
                  Text("第\(num+1)次的结果是\(mydice[num].result)")
                  }

              }
              .onDelete(perform: delete)
              }
          }
          .navigationTitle(Text("共计掷骰子\(mydice.count)次"))
          .navigationBarItems(trailing: Button("全部删除"){deleteall()})
          }
          .tabItem {
               Text("result")
               Image(systemName: "star")
           }

       }
       .actionSheet(isPresented: $isshown){
           ActionSheet(title: Text("请选择:"), message: Text("choose a dice with different sides"), buttons: [
                       .default(Text("four sides"), action: {sidenumber=4}),
                       .default(Text("six sides"), action: {sidenumber=6}),
                       .default(Text("ten sides"), action: {sidenumber=10}),
                       .default(Text("twlve sides"), action: {sidenumber=12}),
                       .default(Text("twenty sides"), action: {sidenumber=20}),
                       .default(Text("hundred sides"), action: {sidenumber=100}),
                       .cancel()])

1      

I didn't think more about the code,it is just a task for me,I know that it is a wrong attitude.

func create(){

      DispatchQueue.main.asyncAfter(deadline: .now()+0.1){
              result=self.rolldice()
          }
      DispatchQueue.main.asyncAfter(deadline: .now()+0.2){
          result=self.rolldice()
      }
      DispatchQueue.main.asyncAfter(deadline: .now()+0.3){
          result=self.rolldice()
      }
      DispatchQueue.main.asyncAfter(deadline: .now()+0.4){
          result=self.rolldice()
      }
      DispatchQueue.main.asyncAfter(deadline: .now()+0.5){
          result=self.rolldice()
          save()

      }

  }

I understand the DispatchQueue.main.asyncAfter(),it will run the other code first,when it is come to the time we arranged,it will run the code in its closure.

And CoreHaptics:

 func preparehaptics(){
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else{
            print("not support")
            return
        }
        do{
            self.engine=try CHHapticEngine()
            try engine?.start()
        }catch{
            print(error.localizedDescription)
        }
    }

    func fullfill(){
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else{
            print("really not support")
            return
        }
        var events=[CHHapticEvent]()

        let intensity=CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)
        let sharpness=CHHapticEventParameter(parameterID:.hapticSharpness,value:1)
        let event=CHHapticEvent(eventType: .hapticTransient, parameters: [intensity,sharpness], relativeTime: 1, duration: 2)
        events.append(event)

        do {
            let pattern=try CHHapticPattern(events: events, parameters: [])
            let player=try engine?.makePlayer(with: pattern)
            try player?.start(atTime: 0)
        }catch{
            print(error.localizedDescription)
        }
    }

Ok,now I should continue to study the last project!

1      

Project 19! The last one project, the true beginning of the life of learing ios application development!

Congratulate myself! This has showed my strong willpower and perseverance because I took totally three monthes finishing all the projects.Everyday I spend six hours,you can have a reference and arrange your time,plan properly.

I found a bug in my app of milestone 16 to 18 project,everty time I roll the dice then the result will be saved to context,but the list of rendering all results will have a bad sequence,but only restart the app can the sequence be correct.It is so weird,I will try my best to fix it,wait for me!

And these three challenges are so simple for me,here is code:

(1) add a photo credit.I just place it on the line of country flag,it is a text,we only need to keep it default,the interface is fine.

Text(skiresorts[item].imageCredit)                
.layoutPriority(1)`

(2)loading and saving methods:

var set:Set<String>
  var savekey="favorites"
  init(){
      if let mydata=UserDefaults.standard.data(forKey: savekey){
          print(2)
          if let decodedata=try? JSONDecoder().decode(Set<String>.self, from: mydata){
              print(4)
              self.set=decodedata
             return  // this is important,if you forget the code of this line ,you will always get an empty set.
          }
      }
      self.set=[]

  }
  func save(){
      if let mydata=try? JSONEncoder().encode(self.set){
          print(3)
          UserDefaults.standard.setValue(mydata,forKey: savekey)
      }
  }

The most important thing is this line of code,which I add an annotation.

(3)user sort and filter.

  static var sortname="id"
  static func <(lhs:resorts,rhs:resorts)->Bool{
      switch sortname{
      case "alphabetical":
          return lhs.name<rhs.name

      case "country":
          return  lhs.country<rhs.country

      default:
          return lhs.id<rhs.id
      }

  }

I define a static variable,which type is string.It belongs to resort itself,not an instance of it.I leverage its different values to decide to which way of sorting we should use.As you can see,I use a switch syntax.

func myfilter(_ myresorts:[resorts],_ filterstandard:String,_ filteritem:String)->[resorts]{

  if filterstandard=="country"{
      return myresorts.filter(){$0.country==filteritem}
  }else if filterstandard=="size"{
      if filteritem=="small"{
          return myresorts.filter(){$0.size==1}
      }
      if filteritem=="medium"{
          return myresorts.filter(){$0.size==2}
      }
      if filteritem=="large"{
          return myresorts.filter(){$0.size==3}
      }
  }else if filterstandard=="price"{
      if filteritem=="1"{
          return myresorts.filter(){$0.size==1}
      }
      if filteritem=="2"{
          return myresorts.filter(){$0.size==2}
      }
      if filteritem=="3"{
          return myresorts.filter(){$0.size==3}
      }
  }
  return myresorts
}

This is filter method,with three parameters:myresorts means all of our data;filterstand means which one is our stand of choosing,like country,price and size;filteritem means the specifical value of which country,how much,what is the size.

.navigationBarItems(leading:Button("筛选"){
                    self.skiresorts=myfilter(skiresorts,"country", "United States")
                },trailing: Image(systemName:"list.dash")
                    .contextMenu{

                        Button("default"){
                            resorts.sortname="id"
                            self.skiresorts=skiresorts.sorted()
                        }
                        Button("alphabetical"){
                            resorts.sortname="alphabetical"
                            self.skiresorts=skiresorts.sorted()

                        }
                        Button("country"){
                            resorts.sortname="country"
                            self.skiresorts=skiresorts.sorted()

                        }

                })

There are two buttons,one with one of ways of filtering,another with ".contextMenu".

I found that if you use a "NavigationView",a "List" inside it, a "ForEach" inside List,a "NavigationLink" inside ForEach,you can't add ".navigationBarItem()" to NavigationVeiw,instead you can add it to NavigationLink.

There is ending of our 100 days of swiftUI,but I will review it again,and still update what I learned. GO on!

1      

Final exam!

I have ten wrong!

1      

请问你可以把Project 9 的 Challenge 3 :control the position of the gradient using a property用Slider来呈现吗? 我看到你好像是用Button来呈现的,有没有可能用Slider呈现位置逐渐变化的过程?

1      

I have a try,and find it can be achieved.Here is my code,you can have reference.

First,you should change the colorcyclingrectangle view to this,add four variables,they will be some position points that you can change.

   var startx:Double
    var starty:Double
    var endx:Double
    var endy:Double
ForEach(0..<num){value in
      Rectangle()
          .inset(by: CGFloat(value))
         // .strokeBorder(mycolor(value, 1),lineWidth:2)
          .strokeBorder(LinearGradient(gradient: Gradient(colors: [mycolor(value, 1),mycolor(value, Int(0.5))]), startPoint: .init(x: CGFloat(startx), y: CGFloat(starty)), endPoint:.init(x: CGFloat(endx), y: CGFloat(endy))))

  }

Second, add some appropriate properites to contentView:like this:

 @State private var startx=0.0
    @State private var starty=0.0
    @State private var endx=0.0
    @State private var endy=0.0

    colorcyclerectangle(amount: myamount, num: Int(mynum),startx: startx,starty: starty,endx: endx,endy: endy)

      VStack(spacing:2){
                Text("\(startx,specifier: "%g")")
                Slider(value: $startx,in:0...100)

                Text("\(starty,specifier: "%g")")
                Slider(value: $starty,in:0...100)

                Text("\(endx,specifier: "%g")")
                Slider(value: $endx,in:0...200)

                Text("\(endy,specifier: "%g")")
                Slider(value: $endy,in:0...200)
            }

As all changes done,you can change the position of the gradient with four sliders as you expected.

1      

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.