【Swift】年/月のPickerViewをInt型で作る

こんにちは、@nekokichi1_yos2です。

 

MoneyMonthで年と月だけのPickerViewを作る際、Data型で作る方法が見当たらず、仕方なくInt型で作りました。

 

nekokichi2yos2.hatenablog.com

 

Data型だと、どうしても日にちや時間を含めてしまい、〇〇だけを取得する方法がありません。

 

仮にData型で再利用するなら、Int→Data、に変換でもすればいいんじゃないでしょうか。

 

f:id:nekokichi_yos2:20200313101247p:plain

 

import UIKit

class ViewController: UIViewController,UIScrollViewDelegate,UIPickerViewDelegate,UIPickerViewDataSource {
    
    @IBOutlet weak var textField: UITextField!
    
    var picker = UIPickerView()
    var toolbar = UIToolbar()
    
    //pickerView用で表示させる年と月の変数
    let year = Array<Int>(2000...2050)
    let month = Array<Int>(1...12)
    
    //pickerViewで選択した年月を保持
    var display_year = Int()
    var display_month = Int()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        picker.delegate = self
        picker.dataSource = self
        
        //ツールバー
        toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35))
        //空白(スペース)
        let spacelItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        //完了ボタン
        let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done))
        //空白と完了ボタンをツールバーにセット
        toolbar.setItems([spacelItem, doneItem], animated: true)
        
        //textFieldにpickerViewとtoolbarをセット
        textField.inputView = picker
        textField.inputAccessoryView = toolbar
        
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0:
            return year.count
        case 1:
            return month.count
        default:
            break
        }
        return 0
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case 0:
            return "\(year[row])"
        case 1:
            return "\(month[row])"
        default:
            break
        }
        return ""
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        //pickerViewで選択した値
        display_year = year[pickerView.selectedRow(inComponent: 0)]
        display_month = month[pickerView.selectedRow(inComponent: 1)]
        //textFieldに表示
        textField.text = "\(display_year)/\(display_month)"
    }
    
    @objc func done() {
        //キーボードを閉じる
        self.view.endEditing(true)
    }

}

 

 

【Swift】アプリ制作 - MoneyMonth

こんにちは、@nekokichi1_yos2です。

 

新しいアプリを作りました。

 

その名も、MoneyMonth、です。

 

 

概要は、

  • サブスク、分割/リボ払いをまとめて管理するアプリ
  • 2020/3のように、年月ごとに発生する月額料金を把握できる
  • 商品/サービスの名前、○年/○月の期間、支払日、料金、を設定するだけ

 

YouTubeや動画サービスなどのサブスクは、毎月一定額を決まった日に支払います。

 

利用するサービスが3つ以上もなってくれば、銀行やメールでの明細を見ても、どのサービスのものなのかが把握しづらいです。

 

実際、僕が利用してるネット銀行のアプリでは、料金と支払日が載っていますが、何の商品化が書かれておらず、自分の収支状況がわからない時があります。

 

そこで、既に料金と支払日がわかっている支払いがあるなら、まとめちゃおう!、ということでMoneyMonthを作った次第です。

 

具体的なコードは、GitHubに載っております。

https://github.com/CatLuck2/MoneyMonth

【Swift】Invalid document reference. Document...について

Firebaseを利用中に下記のエラーに遭遇。

'Invalid document reference. Document references must have an even number of segments, but User has 1'

 

直訳すると、
"ドキュメントを参照できません。参照には偶数のセグメントが必要、しかしユーザーは既に1つ持っています。"
という意味。

 

僕の場合、

db.collection("User").document(userDataClass.userID).getDocument()
↓
db.collection("User").getDocument()

(db = Firestore.firestore())
に直したら治った。

 

原因は、

  • collection > documentの階層が標準
  • collection.add()やcollection.set()ならOK
  • 階層の数が多すぎる/少なすぎる

かな。

 

もう全然わからん!!

【Swift】staticで1つのインスタンスを共有

 

 

解説

 

全ファイルで変数や値を共有したくありませんか?

 

クラスのインスタンスって基本的に生成したファイル内でしか使えません。

 

関数やメソッドなら、渡したい引数さえ用意すれば、後は処理や返り値を返してくれるので、必要な時にインスタンスを作ればいいだけです。

 

しかし、変数の場合はどうでしょうか?

 

インスタンスは1つ1つが別物なので、別のファイルで使うには、逐一渡し続ける必要があります。

 

例えば、インスタンスAを他のファイルで使う場合、関数などで渡します。

f:id:nekokichi_yos2:20190401141700p:plain

 

ですが、もし何十個ものファイルで使う場合、

  • 常に保持し続けないといけない
  • 今現在の変数や値の状態が把握できない
  • 余計にコードが増える

などの弊害が起こります。

f:id:nekokichi_yos2:20190401141638p:plain

 

そこで、使いたいインスタンスを1つのファイルに固定させ、必要なときに呼び出せれば、わざわざ遷移先に渡す必要などありません。

 

お金の管理に例えると、

  • 毎日ランダムで選んだ社員に任せる

ではなく

  • 1つの銀行口座に任せる

です。

f:id:nekokichi_yos2:20190401141526p:plain

 

オリジナルアプリ開発でFirebaseを使った際、どこからでもアクセスできるインスタンスがあれば、新たにデータを取得/編集/保存する際、わざわざバケツリレーしなくても、必要な時に参照するだけでいいのでめっちゃ楽でした。

 

それでは、staticを使った共有インスタンスを使い方を紹介します。

 

ストーリーボード

 

今回は、

  • 画面起動時に初期値と変更後の値
  • 遷移後に現在の値と変更後の値

を表示します。

 

f:id:nekokichi_yos2:20190331174346p:plain

 

ソースコード

 

「呼び出される側」

class object: NSObject {
    //頭にstatic
    //現クラスのインスタンスを代入
    static let instance = object()
    var number = 0
    var string = "a"
}

 

「呼び出す側 - ViewController」

class ViewController: UIViewController {
    
    //object.swift
    let sample = object.instance

    override func viewDidLoad() {
        super.viewDidLoad()
        //インスタンスの初期値
        print("\(sample.number) " + sample.string)
        //値を変更
        sample.number = 100
        sample.string = "string"
        //変更した値を表示
        print("\(sample.number) " + sample.string)
    }

}

 

「呼び出す側 - ViewController2」

class ViewController2: UIViewController {

    //object.swift
    let sample = object.instance
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //インスタンスの初期値
        print("\(sample.number) " + sample.string)
        //値を変更
        sample.number = 777
        sample.string = "end"
        //変更した値を表示
        print("\(sample.number) " + sample.string)
    }
}

 

 

出力結果

f:id:nekokichi_yos2:20190401141114p:plain

1,2行目がViewController、

3,4行目がViewController2、での出力結果。