//tips
//行追加の仕組み理解
ボタンを押すと一度にリストが追加されてしまうので随時追加できる機能を考える。
まずはswiftの配列の仕組みを理解する。
let digits =[ “0”, “1”, “2”, “3” ]
print(digits[2]) = 2
print(digits.count) //要素の個数を表す4を出力
var nums = digits //変数に配列を入れることで、配列を複製することができる
print(nums) //[ “0”, “1”, “2”, “3” ] を出力
var roman = [ “1”, “2”, “3” ]
roman.append(“4”)
print(roman) //[ “1”, “2”, “3”,“4” ]
appendをうまく使えば配列内の要素を随時追加できそう。
単純に
func createTasks()->[String] {
tasks.append("")
//return ["item1", "item2", "item3", "item4", "item5","item6"]
}
としたら下記のエラーが出た。
Cannot convert return expression of type '()' to return type '[String]'
文字列の返り値に()を含むものは返せないということだろうか。
下記を参考にボタンのアクションの方を変更することでボタンクリックで行を追加する機能は実装できた。配列も変更することで最初から記載する文言も掲載できた。
https://note.com/marikooota/n/n2b0cda74b379
import SwiftUI
struct ContentView: View {
@State var tasks = ["リスト1", "リスト2", "リスト3", "リスト4", "リスト5"]
//@State var tasks = [String]()
@State var newtask = ""
var body: some View {
VStack {
NavigationView{
List{
ForEach(0..<tasks.count, id: \.self) { task in
Text(self.tasks[task])}
.onDelete(perform: rowRemove)
}
.navigationBarTitle("Menu")
}
HStack {
Spacer()
Button(action: {
self.tasks.append(self.newtask)
self.newtask = ""
//self.tasks = createTasks()
}) {
Image(systemName:"pencil.tip.crop.circle.badge.plus")
.resizable()
.foregroundColor(/*@START_MENU_TOKEN@*/.black/*@END_MENU_TOKEN@*/)
.padding(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
.scaledToFit()
.frame(width: 80, height: 80)
}
}
}
}
func rowRemove(offsets: IndexSet) {
tasks.remove(atOffsets: offsets)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
テキストの入力にtextfieldを使用できることがわかったのでこちらを組み込んでいく。
https://capibara1969.com/1546/
List内のText部分を置き換えられないか検証する。
List{
ForEach(0..<tasks.count, id: \.self) { task in
Text(self.tasks[task])}
.onDelete(perform: rowRemove)
}
このようにするとCannot convert value of type 'Binding<[String]>' to expected argument type 'Binding<String>’というエラー発生。
List{
ForEach(0..<tasks.count, id: \.self) { task in
TextField("PlainTextFieldStyle", text: $tasks)}
//Text(self.tasks[task])}
.onDelete(perform: rowRemove)
}
TextFieldを配列で使用する際には関数を使う必要があるのかもしれない。こちらも検証する。
https://ja.stackoverflow.com/questions/18877/swift%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6uitextfield%E3%81%AE%E9%85%8D%E5%88%97%E3%82%92%E4%BD%9C%E3%82%8B%E6%96%B9%E6%B3%95
まず関数の理解から。
func 関数名(仮引数:型) ->型{
文・・・
}
の構文で書かれている。
例えば、
var total = 0
func count(n: Int) -> Int{ //関数名countは整数型nを引数とする
total += n //引数nをtotalに加算していく
return total
}
func reset(){total = 0} //引数も型もなく、実行されたらtotalを0にする
上記を踏まえ関数の呼び出しを見ていくと、
let a = 10
Let b = count(n: a - 5) // totalに5を加算し、それをbとする
print(“\(b)”) //結果5
print(“\(count(n: a))”) //10を新たな引数とし、totalに加算、すでに5があるので15が結果となる。
関数の実行は
関数名(引数名:引数に代入する値または式)
で表される
また、関数の中身に式がなくreturnのみで表される場合は省略することが可能になる。
func messageA() -> String{
return “現在の値は\(total)です。”
}
逆に、関数の引数が複数あり、わかりづらい場合は、複数の仮引数をもち、
func buy(product:Int, price:Int, quality:Int){
print (“Product:\(product), amount =\(price * quality)”)
}
とややこしくなり、呼び出す際には
buy(product:10000, price:22222, quantity:10)
の形で呼び出されることになる。
このように引数ラベルを複数書かなければならないほどのラベルではなく、呼び出しの際には省略して良いと考える場合には、
func are(_ h:Double, _ w:Double) -> Double{
return h * w
}
呼び出しで
let a = are(10.0,12.5)とh:およびw:の部分を呼び出しの際に書かなくてよくなる。
コードをなるべくシンプルに書きたい時には_は重宝されそう。
念のため構造体についても見直す。
struct SimpleDate{
var year: Int
var month: Int
var day: Int
}
このSimpleDate構造体をSimpleDate()でインスタンス生成するためには全て初期値が必要なので
struct SimpleDate{
var year = 2010
var month = 7
var day = 28
var d = SimpleDate()
}
などと入力される。
一方で、初期値が与えられていない場合、
struct AnotherDate{
var month, day : Int
var year = 1998
}
インスタンスを生成する場合は引数を取る必要があり、
var move =Another(month:8, day:8)
と与えられていない引数の値を入れてあげる必要がある。
構造体は値型のため、定数が代入されたインスタンスでは各プロパティの値を変更できない。
つまり、let event =SimpleDate(year:2000, month:9, day:13)が一旦生成されてしまうとyear, month,dayは後で変更することができなくなる。
struct Time{
let in24h: Bool = false
var hour = 0, min = 0
}
とした場合、
var t2 = Time(in24h:true, hour:7, min:0) //定数部分であるためin24hは変更できない
var t2 = Time(hour:7, min:0)//変数部分であるため変更可能
ここでよく使われるinit()についても確認する。
struct SimpleDate{
var year, month, day: Int
init(){
year = 2095; month = 10; day = 31
}
}
などのように使われるが、
これは
struct SimpleDate{
var year: Int = 2095
var month: Int = 10
var day: Int = 31
}
とすることもできる。
Initは必ずしも使わなければいけないというわけではないが、要素の整理などのため便利だから使われるという理由があるよう。
複数のイニシャライザを設定することもできる。同じ関数名で引数の型や個数が異なる際に使われる。
struct Time{
let in24h:Bool
var hour = 0, min = 0
init(hour:Int, min:Int){
int24 =false
self.hour = hour
self.min = min
}
init(hourIn24 h:Int){
in24h = true
hour = h
}
init(_ hour:Int){
self.init(hourIn24: hour)
}
}
この関数の呼び出しは、
var a = Time(hour:10, min:30) //12時制 10:30
var b = Time(hourIn24:15) //24時制 15:00
var c = Time(1) //24時制 1:00
となる。
構造体をプロパティに持つ子構造体は
struct DateWithTime{
var date = SimpleDate()
var time = Time(hour:0, min:15)
}
呼び出しは
var u = DateWithTime()
print(u.date.year)
print(u.time.min)
のように他の構造体の値をひっぱってこれる。