//tips
//swiftでのメソッドの使用
メソッドは構造体の一部として関数を定義することにより行い、インスタンスのプロパティとメソッドにアクセスできる。いまいちよくわからない。
例を見た方がわかりやすいのでメソッド定義を持つ構造体を下記に記載する。
struct Time{
let hour, min : Int
func advanced(min:Int) ->Time{ //現在時刻に分minを加算するメソッド
var m = self.main +min
var h = self.hour
if m >= 60{
h = (h +m/60)%24 //%は剰余の値
m%=60
}
return Time(hour:h, min:m) //新しいインスタンスを返す}
func toString() -> String{ //時刻を文字列として返す
let h = hour < 10 ? “\(hour)”:“\(hour)”
let m = min < 10 ? “0\(min)”:“\(min)”
return h +”:” + m
}
}
今まで引っかかっていた機能の「属性部分」に「構造体」がくる謎は、メソッドで新しいインスタンスを返す仕組みであったことがわかり、理解が深まった。
これを呼び出すと
let t1 = Time(hour:22, min:45)
let t2 = t1.advanced(min:140)
print(t1.toStrong()) //22:45
print(t2.toStrong()) //1:05
t1は最初のlet hour, min : Intから作成することができる。
t2はメソッドを用いて、t1に基づいた新たなインスタンスを作成する。t1に140分追加したもの。
toStringはTime型を文字列に変更することができるので、print表示の時に利用する。
メソッドにも、インスタンスの内容そのものを変えるものと属性を変えるものなどの種類があることがわかる。この何を変えるかが{}前の設定ワードとして理解する。
これでtextfieldの下記のコードの使い方もわかるようになってきた。
func makeUITextField(frame: CGRect, DataNum: Int) -> [UITextField] {
var textFields:[UITextField] = []
for var i = 0; i < DataNum; i++ {
let textField:UITextField = UITextField.init(frame: frame)
textField.borderStyle = UITextBorderStyle.RoundedRect
textField.keyboardType = UIKeyboardType.Default
textField.returnKeyType = UIReturnKeyType.Done
textField.delegate = self
textFields.append(textField)
self.view.addSubview(textField)
}
return textFields
}
アプリへの文字入力に関して下記のtext: $tasksの内容をBinding<String>型に書き換えることで、文字入力ができるようになった。
<変更前>
List{
ForEach(0..<tasks.count, id: \.self) { task in
TextField("PlainTextFieldStyle", text: $tasks)}
//Text(self.tasks[task])}
.onDelete(perform: rowRemove)
}
<変更後>
List{
ForEach(0..<tasks.count, id: \.self) { index in
TextField("PlainTextFieldStyle", text: $tasks[index])}
//Text(self.tasks[task])}
.onDelete(perform: rowRemove)
}
Bindingとは、SwiftUIで変数を変更可能にするもので、SwiftUIは、View側のBindingを使うことで変数などの変更を即表示させることが可能となる。
TextFieldの引数textはBinding<String>型なので@Stateなどの文字列変数をBindingすることになる。今回Bindingしたのは@State var tasksである。
ForEachの使い方も確認する。ForEachは複数のViewを生成するので、FormやList、VStackなどのコンテナ内に記述する手法がメインとなる。
例えば
struct ContentView: View {
var body: some View {
Form {
ForEach(1..<6) { num in
Text("\(num)行目")
}
}
}
}
とした場合、1..<6「1以上6未満」の範囲を指定し、引数をinの前に置き、num inとし、numに1から順に数値を入れていくことになる。
この引数が組み込まれている式などがinの後に続き、順に値を出していく。
これが配列の場合は、
struct ContentView: View {
let animals = ["カラス”, "アシタカ”, "トトロ”, "アシカ”]
var body: some View {
Form {
ForEach(0..<animals.count) { num in
Text(self.animals[num])
}
}
}
}
.countで配列の中の要素数を最大とし、0から繰り返しを行う。既に上文でインスタンス化されているanimalsをselfと[num]を用いて、中身を取り出している。
但しこの方式が使えるのは、データの変更(削除・並び替え)が発生しない出力専用として使う場合のみで、データの変更がある場合、id指定で各要素の独立性を担保する。
struct ContentView: View {
var animals = ["カラス”, "アシタカ”, "トトロ”, "アシカ”]
var body: some View {
Form {
ForEach(animals, id: \.self) { animal in
Text(animal)
}
}
}
}
各要素のインスタンスを示す.selfを用いて、該当要素を識別するidとしている。
下記を参考にした。
https://capibara1969.com/1650/
//swiftUIでの変更テキストの保存方法を考える
swiftではuserdefaultsを使用することでローカル環境にデータ保存ができる。
単純に下記を追加するだけでは保存できないようなので例文から知らないコード部分を把握していく。
var userDefaults = UserDefaults.standard
let tasks = userDefaults.array(forKey: "キー")
userDefaults.set(tasks, forKey: "キー")
https://qiita.com/ryomaDsakamoto/items/6c25d8c39c1fe6cf3d7a
https://qiita.com/k_eita/items/d36b4cffd9fc6e133c70
https://swiswiswift.com/2020-06-27/
まず、userDefaultsの宣言時に一緒に記載されている下記内容を確認する。
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
overrideは、親クラスで宣言されたプロパティやメソッドを子クラスで上書きする機能で、viewDidLoad()メソッドがViewControllerとUIViewControllerの両方に定義されているため、上書きしている。
メソッドの一部を上書きする際ためsuper(親クラス)を記載している。
viewDidLoadは、ViewControllerのMainViewが読み込まれると呼び出されるメソッドで、ビューの最初の設定がロードされたら、関数をオーバーライドする必要がある。
このロードとはViewControllerの実行処理の順序に関係しており、データの読み込みのことであるが、viewDidLoad()はデータ読み込み後に実行されるメソッドでviewに対する追加の初期化処理の際などを行う。
https://medium.com/@shiba1014/viewcontroller%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB-37151427bda5
実際にいつ、どのような形で必要になるのかの目安として下記のようなコードを見つけたので記載する。
class PrintingViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("view has loaded")
}
}
class UserViewController: PrintingViewController {
override func viewDidLoad() {
super.viewDidLoad()
// do view setup here
}
}
ここではviewDidLoadを上書きしないと、PrintingViewController変更分のviewDidLoadコードを実行できない。
このような場合に備えて override func viewDidLoad() が記載されている。
SwiftでUserDefaultsを利用すると、データを記録して、次回起動時にそれを読み込んで利用することができる。その保存を内容の更新タイミングで行わせる必要がある。
また、最初は保存データがなく、nilが返されますので、その対応も考える必要がある。
現在UserDefaultsの定義を行い、Textfeildでの変更修正分をtasks = userDefaults.array(forKey: "キー”)で変数に代入し直した上でtasks = userDefaults.array(forKey: "キー”)と保存しているが、エラーが発生している。C#のplayerprefの際に想定できた問題とは違うところで問題が発生しているよう。
こちらが参考になるシンプルなUserDefaultsの使用説明。
調べていく中でSwiftのListは単純に配列とは言えず、arrayとは別物であることがわかった。
Listは「RealmSwift」というRealmを扱うためのライブラリで扱える型らしく、Realmとは、iOSおよびAndroid用のクロスプラットフォームモバイルデータベースで、iphoneにデータを保存しておくことができるデータベースとのこと。
https://qiita.com/ottijp/items/35dee1c03e055e450c81