Xcode」カテゴリーアーカイブ

【Swift5】ディクショナリ等に入れるDate型の初期値の設定が面倒。

タイトルのままですが、[String:Any]等で、AnyにはString型Bool型Int型等ダイレクトに入力できる物が多いのですが、Date型も入れれないのかと考えてみました。
結局よくわからず、String型で日時を作ってDateFormatterを設定してDate型に変換してから出ないと無理っぽい感じでした。

なのでやったことの忘備録です。

import UIKit

let dateNow = Date() //現在の時刻
var dateDic: [String:Any] = [:] //ディクショナリ型

//①ディクショナリ型に直接date型を入れたいが無理っぽい。
dateDic["dateNow"] = dateNow
dateDic["dateString"] = "2020-04-20 11:15:17 +0000"

print(dateDic["dateNow"] as! Date)
//print(dateDic["dateString"] as! Date )  //String型なので当然エラーになる


//②なのでDate型を作るためにDateFormatterをセット
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")//USなので時差に注意。
dateFormatter.dateFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss'"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)

//文字列をDateFormatterでDate型にして辞書に収納
let string = "2020-04-20 11:15:17"
let dateString = dateFormatter.date(from: string)
dateDic["dateString"] = dateString

print(dateDic["dateString"] as! Date) //Date型として出せる。

//③おまけDate型を日本用に出力。
let f = DateFormatter()
f.timeStyle = .full
f.dateStyle = .full
f.locale = Locale(identifier: "ja_JP")//日本なので時差に注意。

print(f.string(from: dateDic["dateString"] as! Date))

こんなんでます。

2020-04-20 23:38:46 +0000
2020-04-20 11:15:17 +0000
2020年4月20日 月曜日 20時15分17秒 日本標準時

ちょいとめんどいですね。

【Swift5】アプリがバックグラウンドに入った時の処理。

なんか以前はappDelegateを使ってたよーな気がしたんだけど調べ直してみた。

import UIKit

class ViewController: UIViewController, UIApplicationDelegate{

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
     
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(ViewController.background),//通知来た時の処理先
                                               name: UIApplication.willResignActiveNotification,
                                               object: nil)
    }
    
    @objc func background() {
        print("ばっくぐらうんど通知来た")
    }
}

抜粋なんで動かんかったらすまん。
こんなんで動くと思う。/(^o^)\

【Swift5】pickerViewを2つ(以上)とdatePickerを設置して下から出るようにする。

定期的にpickerViewのこんな記事を書いている気がします。(^_^;)
pickerViewはよく使うけどアプリをたまにしか作らないのでその間にSwiftのバージョンも上がるし作り方も忘れるよね。

同じViewContorollerに2つ以上のPickerViewを設置し、datePickerも使って、しかも普通のキーボードのように下から出るようにしたい。
それに少し前の記事を参考に閉じるボタンも付けます。それは下記参照。
【Swift5】textFieldのキーボードに閉じるボタンを付ける。 | iPhoneアプリ備忘録

ではまず、3つのtextfieldを作成します。
autoLayoutは適当に。
スクリーンショット 2020-04-11 11.06.09

textfieldはそれぞれあうとれっとせつぞくします。
pickerViewのプロパティを2つと、datePickerのプロパティを作り、pickerViewに表示する配列も作成します。

UIPickerViewDelegate, UIPickerViewDataSourceを設定するとプロトコルに従いメソッドが作成されます。
UITextFieldDelegateも書いておきましょう。
とりあえずここまでのコード。

import UIKit

class ViewController: UIViewController,UITextFieldDelegate,UIPickerViewDelegate, UIPickerViewDataSource {

    //textFieldとのアウトレット接続
    @IBOutlet weak var kanaTextField: UITextField!
    @IBOutlet weak var numberTextField: UITextField!
    @IBOutlet weak var dateTextField: UITextField!

    //pickerViewのプロパティを作る
    var kanaPickerView : UIPickerView = UIPickerView()
    var numberPickerView  : UIPickerView = UIPickerView()
    //datePickerのプロパティを作る
    var datePickerView  :UIDatePicker = UIDatePicker()
    
    //pickerViewに表示する配列を作成
    let list1:[String] = ["いち","に","さん","よん","ご",]
    let list2:[String] = ["1","2","3","4","5","6","7"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        <#code#>
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        <#code#>
    }
}

そして、プロトコルは置いといてキーボードをpickerViewに置き換える辺りの設定します。
基本的にはPickerViewにtagを設定し、textfieldのinputViewに設定します。
datePickerも同様に。
viewDidLoadから呼びます。

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        makePickerKeybord()
    }
    
    //キーボードの設定
    func makePickerKeybord(){
        //かな数字のPickerviewをキーボードにする設定
        kanaPickerView.tag = 1
        kanaPickerView.delegate = self
        kanaTextField.inputView = kanaPickerView
        kanaTextField.delegate = self
        
        //numberのPickerviewをキーボードにする設定
        numberPickerView.tag = 2
        numberPickerView.delegate = self
        kanaTextField.inputView = numberPickerView
        kanaTextField.delegate = self
        
        // 日付ピッカーをキーボードにする設定
        datePickerView.datePickerMode = UIDatePicker.Mode.dateAndTime
        datePickerView.timeZone = TimeZone(identifier: "Asia/Tokyo")
        datePickerView.locale = Locale(identifier: "ja_JP")
        datePickerView.minuteInterval = 15
        datePickerView.addTarget(self, action: Selector(("dateChange")), for: .valueChanged)
        dateTextField.inputView = datePickerView
        dateTextField.delegate = self
    }

pickerViewのプロトコルの設定。
コンポーネントの数は1でコンポーネントに入る配列の数はtagで切り分けます。
コンポーネントの中身、配列もtagで切り分け。

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch pickerView.tag {
        case 1:
            return list1.count
        case 2:
            return list2.count
        default:
            return 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        print("たぐ",pickerView.tag)
        switch pickerView.tag {
            case 1:
                return list1[row]
            case 2:
                return list2[row]
        default:
            return "error"
        }
    }

pickerViewとdatePickerViewに変更があった時に呼ばれてtextFieldのテキストが書き換えられるメソッド。

     //pickerが選択された際に呼ばれるデリゲートメソッド.
     func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
         switch pickerView.tag {
             case 1:
                 return kanaTextField.text = list1[row]
             case 2:
                 return numberTextField.text = list2[row]
         default:
             return
         }
     }
     
     //datePickerが変化すると呼ばれる
    @objc func dateChange(){
         let formatter = DateFormatter()
         formatter.dateFormat = "yyyy年MM月dd日 HH:mm"
         dateTextField.text = "\(formatter.string(from: datePickerView.date))"
     }
}

いちおこれで完成。
IMG_6322

一応全コード

import UIKit

class ViewController: UIViewController,UITextFieldDelegate,UIPickerViewDelegate, UIPickerViewDataSource {

    //textFieldとのアウトレット接続
    @IBOutlet weak var kanaTextField: UITextField!
    @IBOutlet weak var numberTextField: UITextField!
    @IBOutlet weak var dateTextField: UITextField!

    //pickerViewのプロパティを作る
    var kanaPickerView : UIPickerView = UIPickerView()
    var numberPickerView  : UIPickerView = UIPickerView()
    //datePickerのプロパティを作る
    var datePickerView  :UIDatePicker = UIDatePicker()
    
    //pickerViewに表示する配列を作成
    let list1:[String] = ["いち","に","さん","よん","ご",]
    let list2:[String] = ["1","2","3","4","5","6","7"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        makePickerKeybord()
    }
    
    //キーボードの設定
    func makePickerKeybord(){
        //かな数字のPickerviewをキーボードにする設定
        kanaPickerView.tag = 1
        kanaPickerView.delegate = self
        kanaTextField.inputView = kanaPickerView
        kanaTextField.delegate = self
        
        //numberのPickerviewをキーボードにする設定
        numberPickerView.tag = 2
        numberPickerView.delegate = self
        numberTextField.inputView = numberPickerView
        numberTextField.delegate = self
        
        // 日付ピッカーをキーボードにする設定
        datePickerView.datePickerMode = UIDatePicker.Mode.dateAndTime
        datePickerView.timeZone = TimeZone(identifier: "Asia/Tokyo")
        datePickerView.locale = Locale(identifier: "ja_JP")
        datePickerView.minuteInterval = 15
        datePickerView.addTarget(self, action: Selector(("dateChange")), for: .valueChanged)
        dateTextField.inputView = datePickerView
        dateTextField.delegate = self
    }
    
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch pickerView.tag {
        case 1:
            return list1.count
        case 2:
            return list2.count
        default:
            return 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch pickerView.tag {
            case 1:
                return list1[row]
            case 2:
                return list2[row]
        default:
            return "error"
        }
    }
    
     //pickerが選択された際に呼ばれるデリゲートメソッド.
     func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
         switch pickerView.tag {
             case 1:
                 return kanaTextField.text = list1[row]
             case 2:
                 return numberTextField.text = list2[row]
         default:
             return
         }
     }
     
     //datePickerが変化すると呼ばれる
    @objc func dateChange(){
         let formatter = DateFormatter()
         formatter.dateFormat = "yyyy年MM月dd日 HH:mm"
         dateTextField.text = "\(formatter.string(from: datePickerView.date))"
     }
}

// MARK: - キーボードにと閉じるボタンを付ける
//storybordで該当テキストフィールドを選択し、identity Inspectorでclassを DoneTextFierdに切り替える
class DoneTextFierd: UITextField{

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit(){
        let tools = UIToolbar()
        tools.frame = CGRect(x: 0, y: 0, width: frame.width, height: 40)
        let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let closeButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.closeButtonTapped))
        tools.items = [spacer, closeButton]
        self.inputAccessoryView = tools
    }

    @objc func closeButtonTapped(){
        self.endEditing(true)
        self.resignFirstResponder()
    }
}

【Swift5】scrollViewを使って画面下にあるtextfieldがキーボードで隠れないようにした。

入力フォームなどで縦に長くなった時、下の方のtextFieldがキーボードに隠れて困ることがよくあります。
それを解消しました。
前回の記事のようにscrollViewとstackViewを使っている場合に便利です。

参考サイト
Swift:TextFieldが隠れちゃうのをなんとかする!|プログラミング初心者のプロへの道
UITextFieldを使用する時に必要なあれこれ – Qiita
[Swift4]複数のTextFieldがキーボードに隠れて入力できない時の対策 – あなたにフィット

上記2つのサイトを参考にSwift5で簡単に書いてみます。

まずは前々回の記事を参考にscrollView – stackView – view – textfieldという階層を作ります。
【Swift5】縦長のスクロール画面をscrollViewとstackViewを使って作ると便利だった。改訂版 | iPhoneアプリ備忘録
わかりやすくViewの色を塗り分けておきます。
スクリーンショット 2020-04-10 21.03.20

0vz6x-pfv2f

あと、前回の記事を参考にキーボードを閉じるボタンも付けておきます。
【Swift5】textFieldのキーボードに閉じるボタンを付ける。 | iPhoneアプリ備忘録

このままだとスクロールはしますが一番下の青のtextfieldに入力しようとしても隠れて見えません。
キーボードが出た時にキーボードの高さ分だけスクロールビューを動かします。
以下コード

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        configureObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        removeObserver()
        super.viewWillDisappear(animated)
    }
    
    // MARK: キーボードでスクロール変更
    //キーボードの出現でスクロールビューを変更するのを監視用オブザーバー
    func configureObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        //ここでUIKeyboardWillShowという名前の通知のイベントをオブザーバー登録をしている
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
        //ここでUIKeyboardWillHideという名前の通知のイベントをオブザーバー登録をしている
    }
    
    func removeObserver() {
        NotificationCenter.default.removeObserver(self)
    }

        //UIKeyboardWillShow通知を受けて、実行される関数
    @objc func keyboardWillShow(_ notification: NSNotification){
        guard let userInfo = notification.userInfo else { return }
        let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        scrollView.contentInset.bottom = keyboardSize
    }
       
       
       //UIKeyboardWillShow通知を受けて、実行される関数
    @objc func keyboardWillHide(_ notification: NSNotification){
        scrollView.contentInset = .zero
        scrollView.scrollIndicatorInsets = .zero
       }
}

// MARK: - キーボードにと閉じるボタンを付ける
//storybordで該当テキストフィールドを選択し、identity Inspectorでclassを DoneTextFierdに切り替える
class DoneTextFierd: UITextField{

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit(){
        let tools = UIToolbar()
        tools.frame = CGRect(x: 0, y: 0, width: frame.width, height: 40)
        let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let closeButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.closeButtonTapped))
        tools.items = [spacer, closeButton]
        self.inputAccessoryView = tools
    }

    @objc func closeButtonTapped(){
        self.endEditing(true)
        self.resignFirstResponder()
    }
}

こんな感じになります。
2hafl-4l5jh

【Swift5】textFieldのキーボードに閉じるボタンを付ける。

textFieldのキーボードに閉じるボタンを付けたいときがあります。

参考サイト
swiftで閉じるボタンのついたキーボードを表示するUITextFieldクラスの作成 – Qiita

ほぼ劣化コピペです。
元サイトがなくなったら困るので自分用です。
不都合があれは削除します。(-人-)

UITextFieldのカスタムクラスになります。
以下のコードをコードの最後に追記。

// MARK: - キーボードにと閉じるボタンを付ける
//storybordで該当テキストフィールドを選択し、identity Inspectorでclassを DoneTextFierdに切り替える
class DoneTextFierd: UITextField{

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit(){
        let tools = UIToolbar()
        tools.frame = CGRect(x: 0, y: 0, width: frame.width, height: 40)
        let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let closeButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.closeButtonTapped))
        tools.items = [spacer, closeButton]
        self.inputAccessoryView = tools
    }

    @objc func closeButtonTapped(){
        self.endEditing(true)
        self.resignFirstResponder()
    }
}

そして適用したいtextFieldのidentity Inspectorでcustom classをDoneTextFierdに変更する。
スクリーンショット 2020-04-10 21.23.40

これでDone付きのキーボードが出るようになります。
スクリーンショット 2020-04-10 21.28.12

【Swift5】縦長のスクロール画面をscrollViewとstackViewを使って作ると便利だった。改訂版

【Swift4】縦長のスクロール画面をscrollViewとstackViewを使って作ると便利だった。 | iPhoneアプリ備忘録

上記ページのやり方でスクロールビューを作ってるとエラーが出た。
Xcode11でInterface Builderの仕様が変わったらしい。
参考サイト
Xcode11のIBに追加されたContentLayoutGuideとFrameLayoutGuideについて – Qiita

なので改訂版です。
旧ページの画像を使ったりするので整合性がなかったらご指摘ください。/(^o^)\

まず、Safe AreaにScroll Viewを配置します。
Add New Constraintsで上下左右全てのマージンを0とします。
スクリーンショット 2019-01-06 20.41.39

このようなエラーが出ますが続けます。
スクリーンショット 2020-04-03 12.29.31

次いで、そのScroll Viewの中にVertical Stack Viewを配置し、Add New Constraintsで上と左右のマージンを0とします。
スクリーンショット 2020-04-03 13.19.10

ここでXcode11から変更された「Content Layout Guide」を使用します。
現状ではScrollViewの幅と高さが決まっていないためエラーになっています。
なのでStack ViewからContent Layout Guideへ右ドラックで接続しEqual Widthsを選択します。スクリーンショット 2020-04-03 12.30.10

スクリーンショット 2020-04-03 12.31.06

同様にEqual hightsも接続します。
スクリーンショット 2020-04-03 12.31.21

幅は画面幅で設定されるのですが高さが決まらないためエラーが出てますが、Stack Viewに子ビューを入れて高さを決定するとエラーが無くなります。
スクリーンショット 2020-04-03 13.51.43

スクリーンショット 2020-04-03 14.01.41

縦長な画面でテストします。
操作するViewを選んで、simulated sizeを「freeform」にして、heightを設定します。
とりあえず1200にしてみました。
スクリーンショット 2019-01-06 20.51.30

StackViewに高さが200の子Viewを6個入れて分かりやすように色を付けてみました。
スクリーンショット 2019-01-06 21.04.34

これでアプリを起動すると綺麗にスクロールしました。\(^o^)/
zuhqs-9xva4

これだけのことがコードを一行も書かずにできるってすごいなーと思います。\(^o^)/

【Swift5】localeの泥沼【ロケール】

時計や日付関係をイジっててLocaleがよくわからんかった。

言語設定?地域設定(書式設定?)?そのへんがごちゃごちゃです。
それぞれお互いに影響しているようで、地域設定が同じでも言語設定が変わると表記順が変わったり、
言語設定が同じでも地域設定で表記が変わったりします。
よーわからん。

とりあえず参考サイト
iOS11で変わったロケール – Toyship.org
iOS9から変わったNSLocale.preferredLanguagesの対応を考える – Qiita

重要だと思ったのは、本体の言語設定と地域設定以外に、「アプリ側の多言語対応」(Localized)も関係しているようです。
ややこしい。

以下のコードでいろいろ呼び出せるようです。
新規プロジェクトで試してみました。

        print("ロケールカレント!" , Locale.current.identifier) //アプリのLocalizeの言語設定と、本体の地域設定
        print("ロケールランゲージコード!" , Locale.current.languageCode!) //アプリのLocalizeの言語設定
        print("ロケールリージョンコード!" , Locale.current.regionCode!) //本体の地域設定
        print("ロケール!" , Locale.preferredLanguages.first!) //本体の言語設定と、本体の地域設定

デバッグエリアでは

ロケールカレント! en_JP
ロケールランゲージコード! en
ロケールリージョンコード! JP
ロケール! ja-JP

といった感じです。
本体の言語設定だけ取り出すんはどしたらええんや、
あと、間に入るのはハイフンなのかアンダースコアなのか。。。

おまけ。
いろいろといじってるとコンナン出てきた。

        print("Locale.availableIdentifiers" , Locale.availableIdentifiers)
        print("Locale.isoLanguageCodes" , Locale.isoLanguageCodes)
        print("Locale.isoRegionCodes" , Locale.isoRegionCodes)
        print("Locale.isoCurrencyCodes" , Locale.isoCurrencyCodes)
        print("Locale.commonISOCurrencyCodes" , Locale.commonISOCurrencyCodes) 

これを動かすとデバッグエリアでは

Locale.availableIdentifiers ["eu", "hr_BA", "en_CM", "en_BI", "rw_RW", "ast", "en_SZ", "he_IL", "ar", "uz_Arab", "en_PN", "as", "en_NF", "ks_IN", "es_KY", "rwk_TZ", "zh_Hant_TW", "en_CN", "gsw_LI", "ta_IN", "th_TH", "es_EA", "fr_GF", "ar_001", "en_RW", "tr_TR", "de_CH", "ee_TG", "en_NG", "fr_TG", "az", "fr_SC", "es_HN", "en_AG", "ccp_IN", "ru_KZ", "gsw", "dyo", "so_ET", "zh_Hant_MO", "de_BE", "nus_SS", "km_KH", "my_MM", "mgh_MZ", "ee_GH", "es_EC", "kw_GB", "rm_CH", "en_ME", "nyn", "mk_MK", "bs_Cyrl_BA", "ar_MR", "es_GL", "en_BM", "ms_Arab", "en_AI", "gl_ES", "en_PR", "ff_CM", "ne_IN", "or_IN", "khq_ML", "en_MG", "pt_TL", "en_LC", "iu_CA", "ta_SG", "jmc_TZ", "om_ET", "lv_LV", "es_US", "en_PT", "vai_Latn_LR", "en_NL", "to_TO", "cgg_UG", "en_MH", "ta", "zu_ZA", "shi_Latn_MA", "es_FK", "ar_KM", "en_AL", "brx_IN", "te", "chr_US", "yo_BJ", "fr_VU", "pa", "tg", "kea", "ksh_DE", "sw_CD", "te_IN", "fr_RE", "th", "ur_IN", "yo_NG", "ti", "es_HT", "es_GP", "guz_KE", "tk", "kl_GL", "ksf_CM", "mua_CM", "lag_TZ", "lb", "fr_TN", "es_PA", "pl_PL", "to", "hi_IN", "dje_NE", "es_GQ", "en_BR", "kok_IN", "pl", "fr_GN", "bem", "ha", "ckb", "es_CA", "lg", "tr", "en_PW", "tt", "en_NO", "nyn_UG", "sr_Latn_RS", "gsw_FR", "pa_Guru", "he", "qu_BO", "ps_AF", "lu_CD", "mgo_CM", "sn_ZW", "en_BS", "da", "ps", "ln", "pt", "hi", "lo", "ebu", "de", "gu_IN", "wo_SN", "seh", "en_CX", "en_ZM", "fr_HT", "fr_GP", "pt_GQ", "lt", "lu", "es_TT", "ln_CD", "vai_Latn", "el_GR", "lv", "en_KE", "sbp", "hr", "en_CY", "es_GT", "twq_NE", "zh_Hant_HK", "kln_KE", "fr_GQ", "chr", "hu", "es_UY", "fr_CA", "ms_BN", "en_NR", "mer", "shi", "es_PE", "fr_SN", "bez", "sw_TZ", "wae_CH", "kkj", "hy", "dz_BT", "en_CZ", "teo_KE", "teo", "en_AR", "ar_JO", "yue_Hans_CN", "mer_KE", "khq", "ln_CF", "nn_NO", "es_SR", "en_MO", "ar_TD", "dz", "ses", "en_BW", "en_AS", "ar_IL", "es_BB", "bo_CN", "nnh", "teo_UG", "hy_AM", "ln_CG", "sr_Latn_BA", "en_MP", "ksb_TZ", "ar_SA", "smn_FI", "ar_LY", "en_AT", "so_KE", "fr_CD", "af_NA", "en_NU", "es_PH", "en_KI", "en_JE", "lkt", "en_AU", "fa_IR", "pt_FR", "uz_Latn_UZ", "zh_Hans_CN", "ewo_CM", "fr_PF", "ca_IT", "es_GY", "en_BZ", "ar_KW", "pt_GW", "fr_FR", "am_ET", "en_VC", "es_DM", "fr_DJ", "fr_CF", "es_SV", "en_MS", "pt_ST", "ar_SD", "luy_KE", "gd_GB", "de_LI", "it_VA", "fr_CG", "pt_CH", "ckb_IQ", "zh_Hans_SG", "en_MT", "ha_NE", "en_ID", "ewo", "af_ZA", "os_GE", "om_KE", "nl_SR", "es_ES", "es_DO", "ar_IQ", "fr_CH", "nnh_CM", "es_SX", "es_419", "en_MU", "en_US_POSIX", "yav_CM", "luo_KE", "dua_CM", "et_EE", "en_IE", "ak_GH", "rwk", "es_CL", "kea_CV", "fr_CI", "ckb_IR", "fr_BE", "se", "en_NZ", "en_MV", "en_LR", "es_PM", "en_KN", "nb_SJ", "ha_NG", "sg", "sr_Cyrl_RS", "ru_RU", "en_ZW", "sv_AX", "ga_IE", "si", "wo", "en_VG", "ff_MR", "ky_KG", "agq_CM", "mzn", "fr_BF", "naq_NA", "mr_IN", "en_MW", "de_AT", "az_Latn", "en_LS", "ka", "sk", "sl", "sn", "sr_Latn_ME", "fr_NC", "so", "is_IS", "twq", "ig_NG", "sq", "fo_FO", "sr", "tzm", "ga", "om", "en_LT", "bas_CM", "se_NO", "ki", "nl_BE", "ar_QA", "gd", "sv", "kk", "rn_BI", "es_CO", "az_Latn_AZ", "kl", "or", "es_AG", "ca", "en_VI", "km", "os", "sw", "en_MY", "kn", "en_LU", "fr_SY", "ar_TN", "en_JM", "fr_PM", "ko", "fr_NE", "ce", "fr_MA", "gl", "ru_MD", "es_BL", "saq_KE", "ks", "fr_CM", "lb_LU", "gv_IM", "fr_BI", "en_LV", "en_KR", "es_NI", "en_GB", "kw", "nl_SX", "dav_KE", "tr_CY", "ky", "en_UG", "es_BM", "en_TC", "es_AI", "ar_EG", "fr_BJ", "gu", "es_PR", "fr_RW", "gv", "lrc_IQ", "sr_Cyrl_BA", "es_MF", "fr_MC", "cs", "bez_TZ", "es_CR", "asa_TZ", "ar_EH", "fo_DK", "ms_Arab_BN", "ccp", "en_JP", "sbp_TZ", "en_IL", "lt_LT", "mfe", "en_GD", "es_LC", "cy", "ug_CN", "ca_FR", "es_BO", "en_SA", "fr_BL", "bn_IN", "uz_Cyrl_UZ", "lrc_IR", "az_Cyrl", "en_IM", "sw_KE", "en_SB", "pa_Arab", "ur_PK", "haw_US", "ar_SO", "en_IN", "fil", "fr_MF", "en_WS", "es_CU", "es_BQ", "ja_JP", "fy_NL", "en_SC", "yue_Hant_HK", "en_IO", "pt_PT", "en_HK", "en_GG", "fr_MG", "de_LU", "tzm_MA", "es_BR", "en_TH", "en_SD", "nds_DE", "shi_Tfng", "ln_AO", "as_IN", "en_GH", "ms_MY", "ro_RO", "jgo_CM", "es_CW", "dua", "en_UM", "es_BS", "en_SE", "kn_IN", "en_KY", "vun_TZ", "kln", "lrc", "en_GI", "ca_ES", "rof", "pt_CV", "kok", "pt_BR", "ar_DJ", "yi_001", "fi_FI", "zh", "es_PY", "ar_SS", "mua", "sr_Cyrl_ME", "vai_Vaii_LR", "en_001", "nl_NL", "en_TK", "fr_DZ", "en_SG", "ca_AD", "si_LK", "sv_SE", "pt_AO", "vi", "xog_UG", "xog", "en_IS", "nb", "seh_MZ", "es_AR", "sk_SK", "en_SH", "ti_ER", "nd", "az_Cyrl_AZ", "zu", "ne", "nd_ZW", "el_CY", "en_IT", "nl_BQ", "da_GL", "ja", "rm", "fr_ML", "rn", "en_VU", "rof_TZ", "ro", "ebu_KE", "ru_KG", "en_SI", "sg_CF", "mfe_MU", "nl", "brx", "bs_Latn", "fa", "zgh_MA", "en_GM", "shi_Latn", "en_FI", "nn", "en_EE", "ru", "yue", "kam_KE", "fur", "vai_Vaii", "ar_ER", "rw", "ti_ET", "ff", "luo", "fa_AF", "nl_CW", "es_MQ", "en_HR", "en_FJ", "fi", "pt_MO", "be", "en_US", "en_TO", "en_SK", "bg", "ru_BY", "it_IT", "ml_IN", "gsw_CH", "qu_EC", "fo", "sv_FI", "en_FK", "nus", "ta_LK", "vun", "sr_Latn", "es_BZ", "fr", "en_SL", "bm", "es_VC", "ar_BH", "guz", "bn", "bo", "ar_SY", "es_MS", "lo_LA", "ne_NP", "uz_Latn", "be_BY", "es_IC", "sr_Latn_XK", "ar_MA", "pa_Guru_IN", "br", "luy", "kde_TZ", "es_AW", "bs", "fy", "fur_IT", "hu_HU", "ar_AE", "en_HU", "sah_RU", "zh_Hans", "en_FM", "fr_MQ", "ko_KP", "en_150", "en_DE", "ce_RU", "en_CA", "hsb_DE", "sq_AL", "en_TR", "ro_MD", "es_VE", "tg_TJ", "fr_WF", "mt_MT", "kab", "nmg_CM", "ms_SG", "en_GR", "ru_UA", "fr_MR", "zh_Hans_MO", "de_IT", "ccp_BD", "ff_GN", "bs_Cyrl", "tt_RU", "nds_NL", "es_KN", "sw_UG", "yue_Hans", "ko_KR", "en_DG", "bo_IN", "en_CC", "shi_Tfng_MA", "lag", "it_SM", "os_RU", "en_TT", "ms_Arab_MY", "sq_MK", "es_VG", "bem_ZM", "kde", "ar_OM", "kk_KZ", "cgg", "bas", "kam", "wae", "es_MX", "sah", "zh_Hant", "en_GU", "fr_MU", "fr_KM", "ar_LB", "en_BA", "en_TV", "sr_Cyrl", "mzn_IR", "es_VI", "dje", "kab_DZ", "fil_PH", "se_SE", "vai", "hr_HR", "bs_Latn_BA", "nl_AW", "dav", "so_SO", "ar_PS", "en_FR", "uz_Cyrl", "ff_SN", "en_BB", "ki_KE", "en_TW", "naq", "en_SS", "mg_MG", "mas_KE", "en_RO", "en_PG", "mgh", "dyo_SN", "mas", "agq", "bn_BD", "haw", "yi", "nb_NO", "da_DK", "en_DK", "saq", "ug", "cy_GB", "fr_YT", "jmc", "ses_ML", "en_PH", "de_DE", "ar_YE", "es_TC", "bm_ML", "yo", "lkt_US", "uz_Arab_AF", "jgo", "sl_SI", "pt_LU", "uk", "en_CH", "asa", "en_BD", "lg_UG", "nds", "qu_PE", "mgo", "id_ID", "en_NA", "en_GY", "zgh", "pt_MZ", "fr_LU", "dsb", "mas_TZ", "en_DM", "ta_MY", "es_GD", "en_BE", "mg", "ur", "fr_GA", "ka_GE", "nmg", "en_TZ", "eu_ES", "ar_DZ", "id", "so_DJ", "hsb", "yav", "mk", "pa_Arab_PK", "ml", "en_ER", "ig", "se_FI", "mn", "ksb", "uz", "vi_VN", "ii", "qu", "en_PK", "ee", "ast_ES", "yue_Hant", "mr", "ms", "en_ES", "ha_GH", "it_CH", "sq_XK", "mt", "en_CK", "br_FR", "en_BG", "es_GF", "tk_TM", "sr_Cyrl_XK", "ksf", "en_SX", "bg_BG", "en_PL", "af", "el", "cs_CZ", "fr_TD", "zh_Hans_HK", "is", "ksh", "my", "mn_MN", "en", "it", "dsb_DE", "ii_CN", "eo", "iu", "en_ZA", "smn", "en_AD", "ak", "en_RU", "kkj_CM", "am", "es", "et", "uk_UA"]
Locale.isoLanguageCodes ["aa", "ab", "ace", "ach", "ada", "ady", "ae", "aeb", "af", "afh", "agq", "ain", "ak", "akk", "akz", "ale", "aln", "alt", "am", "an", "ang", "anp", "ar", "arc", "arn", "aro", "arp", "arq", "ars", "arw", "ary", "arz", "as", "asa", "ase", "ast", "av", "avk", "awa", "ay", "az", "ba", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj", "be", "bej", "bem", "bew", "bez", "bfd", "bfq", "bg", "bgn", "bho", "bi", "bik", "bin", "bjn", "bkm", "bla", "bm", "bn", "bo", "bpy", "bqi", "br", "bra", "brh", "brx", "bs", "bss", "bua", "bug", "bum", "byn", "byv", "ca", "cad", "car", "cay", "cch", "ccp", "ce", "ceb", "cgg", "ch", "chb", "chg", "chk", "chm", "chn", "cho", "chp", "chr", "chy", "ckb", "co", "cop", "cps", "cr", "crh", "cs", "csb", "cu", "cv", "cy", "da", "dak", "dar", "dav", "de", "del", "den", "dgr", "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "dv", "dyo", "dyu", "dz", "dzg", "ebu", "ee", "efi", "egl", "egy", "eka", "el", "elx", "en", "enm", "eo", "es", "esu", "et", "eu", "ewo", "ext", "fa", "fan", "fat", "ff", "fi", "fil", "fit", "fj", "fo", "fon", "fr", "frc", "frm", "fro", "frp", "frr", "frs", "fur", "fy", "ga", "gaa", "gag", "gan", "gay", "gba", "gbz", "gd", "gez", "gil", "gl", "glk", "gmh", "gn", "goh", "gom", "gon", "gor", "got", "grb", "grc", "gsw", "gu", "guc", "gur", "guz", "gv", "gwi", "ha", "hai", "hak", "haw", "he", "hi", "hif", "hil", "hit", "hmn", "ho", "hr", "hsb", "hsn", "ht", "hu", "hup", "hy", "hz", "ia", "iba", "ibb", "id", "ie", "ig", "ii", "ik", "ilo", "inh", "io", "is", "it", "iu", "izh", "ja", "jam", "jbo", "jgo", "jmc", "jpr", "jrb", "jut", "jv", "ka", "kaa", "kab", "kac", "kaj", "kam", "kaw", "kbd", "kbl", "kcg", "kde", "kea", "ken", "kfo", "kg", "kgp", "kha", "kho", "khq", "khw", "ki", "kiu", "kj", "kk", "kkj", "kl", "kln", "km", "kmb", "kn", "ko", "koi", "kok", "kos", "kpe", "kr", "krc", "kri", "krj", "krl", "kru", "ks", "ksb", "ksf", "ksh", "ku", "kum", "kut", "kv", "kw", "ky", "la", "lad", "lag", "lah", "lam", "lb", "lez", "lfn", "lg", "li", "lij", "liv", "lkt", "lmo", "ln", "lo", "lol", "loz", "lrc", "lt", "ltg", "lu", "lua", "lui", "lun", "luo", "lus", "luy", "lv", "lzh", "lzz", "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde", "mdf", "mdh", "mdr", "men", "mer", "mfe", "mg", "mga", "mgh", "mgo", "mh", "mi", "mic", "min", "mis", "mk", "ml", "mn", "mnc", "mni", "moh", "mos", "mr", "mrj", "ms", "mt", "mua", "mul", "mus", "mwl", "mwr", "mwv", "my", "mye", "myv", "mzn", "na", "nan", "nap", "naq", "nb", "nd", "nds", "ne", "new", "ng", "nia", "niu", "njo", "nl", "nmg", "nn", "nnh", "no", "nog", "non", "nov", "nqo", "nr", "nso", "nus", "nv", "nwc", "ny", "nym", "nyn", "nyo", "nzi", "oc", "oj", "om", "or", "os", "osa", "ota", "pa", "pag", "pal", "pam", "pap", "pau", "pcd", "pdc", "pdt", "peo", "pfl", "phn", "pi", "pl", "pms", "pnt", "pon", "prg", "pro", "ps", "pt", "qu", "quc", "qug", "raj", "rap", "rar", "rgn", "rif", "rm", "rn", "ro", "rof", "rom", "rtm", "ru", "rue", "rug", "rup", "rw", "rwk", "sa", "sad", "sah", "sam", "saq", "sas", "sat", "saz", "sba", "sbp", "sc", "scn", "sco", "sd", "sdc", "sdh", "se", "see", "seh", "sei", "sel", "ses", "sg", "sga", "sgs", "shi", "shn", "shu", "si", "sid", "sk", "sl", "sli", "sly", "sm", "sma", "smj", "smn", "sms", "sn", "snk", "so", "sog", "sq", "sr", "srn", "srr", "ss", "ssy", "st", "stq", "su", "suk", "sus", "sux", "sv", "sw", "swb", "swc", "syc", "syr", "szl", "ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg", "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tl", "tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi", "tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt", "tum", "tvl", "tw", "twq", "ty", "tyv", "tzm", "udm", "ug", "uga", "uk", "umb", "und", "ur", "uz", "vai", "ve", "vec", "vep", "vi", "vls", "vmf", "vo", "vot", "vro", "vun", "wa", "wae", "wal", "war", "was", "wbp", "wo", "wuu", "xal", "xh", "xmf", "xog", "yao", "yap", "yav", "ybb", "yi", "yo", "yrl", "yue", "za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu", "zun", "zxx", "zza"]
Locale.isoRegionCodes ["AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CP", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TA", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW"]
Locale.isoCurrencyCodes ["ADP", "AED", "AFA", "AFN", "ALK", "ALL", "AMD", "ANG", "AOA", "AOK", "AON", "AOR", "ARA", "ARL", "ARM", "ARP", "ARS", "ATS", "AUD", "AWG", "AZM", "AZN", "BAD", "BAM", "BAN", "BBD", "BDT", "BEC", "BEF", "BEL", "BGL", "BGM", "BGN", "BGO", "BHD", "BIF", "BMD", "BND", "BOB", "BOL", "BOP", "BOV", "BRB", "BRC", "BRE", "BRL", "BRN", "BRR", "BRZ", "BSD", "BTN", "BUK", "BWP", "BYB", "BYN", "BYR", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLE", "CLF", "CLP", "CNH", "CNX", "CNY", "COP", "COU", "CRC", "CSD", "CSK", "CUC", "CUP", "CVE", "CYP", "CZK", "DDM", "DEM", "DJF", "DKK", "DOP", "DZD", "ECS", "ECV", "EEK", "EGP", "EQE", "ERN", "ESA", "ESB", "ESP", "ETB", "EUR", "FIM", "FJD", "FKP", "FRF", "GBP", "GEK", "GEL", "GHC", "GHS", "GIP", "GMD", "GNF", "GNS", "GQE", "GRD", "GTQ", "GWE", "GWP", "GYD", "HKD", "HNL", "HRD", "HRK", "HTG", "HUF", "IDR", "IEP", "ILP", "ILR", "ILS", "INR", "IQD", "IRR", "ISJ", "ISK", "ITL", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRH", "KRO", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LSM", "LTL", "LTT", "LUC", "LUF", "LUL", "LVL", "LVR", "LYD", "MAD", "MAF", "MCF", "MDC", "MDL", "MGA", "MGF", "MKD", "MKN", "MLF", "MMK", "MNT", "MOP", "MRO", "MRU", "MTL", "MTP", "MUR", "MVP", "MVR", "MWK", "MXN", "MXP", "MXV", "MYR", "MZE", "MZM", "MZN", "NAD", "NGN", "NIC", "NIO", "NLG", "NOK", "NPR", "NZD", "OMR", "PAB", "PEI", "PEN", "PES", "PGK", "PHP", "PKR", "PLN", "PLZ", "PTE", "PYG", "QAR", "RHD", "ROL", "RON", "RSD", "RUB", "RUR", "RWF", "SAR", "SBD", "SCR", "SDD", "SDG", "SDP", "SEK", "SGD", "SHP", "SIT", "SKK", "SLL", "SOS", "SRD", "SRG", "SSP", "STD", "STN", "SUR", "SVC", "SYP", "SZL", "THB", "TJR", "TJS", "TMM", "TMT", "TND", "TOP", "TPE", "TRL", "TRY", "TTD", "TWD", "TZS", "UAH", "UAK", "UGS", "UGX", "USD", "USN", "USS", "UYI", "UYP", "UYU", "UZS", "VEB", "VEF", "VND", "VNN", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XEU", "XFO", "XFU", "XOF", "XPD", "XPF", "XPT", "XRE", "XSU", "XTS", "XUA", "XXX", "YDD", "YER", "YUD", "YUM", "YUN", "YUR", "ZAL", "ZAR", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"]
Locale.commonISOCurrencyCodes ["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STN", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VEF", "VND", "VUV", "WST", "XAF", "XCD", "XOF", "XPF", "YER", "ZAR", "ZMW"]

こんな感じです。
1つ目はよく使われる組み合わせかな?
次の2つは言語設定と地域設定それぞれだろうね。
下の2つ通貨コードっぽいですね。
何かの参考になれば。

もひとつオマケの参考サイト
ロケールのリージョンコード | Second Flush

【Swift5】UIPickerViewで2列のピッカーを作る。

UIPickerViewで2列のを作りたかったのですがやり方が分からず少し悩みました。

UIPickerViewの参考サイト
【swift】UIPickerViewを作ってみる(ドラムロール)|株式会社イーガオ
[iPhone] UIPickerView の基本的な設定

特に指定せずとも、一列目がcomponentが0で、二列目が1で良いようです。

簡単にラベル2つとUIPickerViewを配置します。
スクリーンショット 2019-04-07 20.19.07

Classに UIPickerViewDelegate, UIPickerViewDataSource を追加して、
それぞれ
pickerView.delegate = self
pickerView.dataSource = self
でつなぎます。
あとは列数は2,行数と、タイトルと、選択時の動作はswitchのcomponentで分岐します。
以下コード。

import UIKit

class ViewController: UIViewController,UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var label1: UILabel!
    @IBOutlet weak var label2: UILabel!
    @IBOutlet weak var pickerView: UIPickerView!
    let list1:[String] = ["1","2","3","4","5","6","7"]
    let list2:[String] = ["いち","に","さん","よん","ご",]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        pickerView.delegate = self
        pickerView.dataSource = self
        //ピッカーの初期値
//        pickerView.selectRow(<#T##row: Int##Int#>, inComponent: <#T##Int#>, animated: <#T##Bool#>)
        pickerView.selectRow(0, inComponent: 0, animated: false)
        pickerView.selectRow(1, inComponent: 1, animated: false)
        
    }
    
    // ドラムロールの列数
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    
    // ドラムロールの行数
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0:
            return list1.count
        case 1:
            return list2.count
        default:
            return 0
        }
    }

    // ドラムロールの各タイトル
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case 0:
            return list1[row]
        case 1:
            return list2[row]
        default:
            return "error"
        }
    }
    
    // ドラムロール選択時
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch component {
        case 0:
            label1.text = list1[row]
        case 1:
            label2.text = list2[row]
        default:
            break
        }
    }
}

switch文のdefaultは適当です。
動かすと味気ない画面ですがちゃんと動きます。
スクリーンショット 2019-04-07 20.27.35

二列ではなく、画面に複数のUIPickerViewを使いたいときはtagを使うと良いようです。

【Swift4】レビューのリクエストをする。

アプリを使っていると時々突然にアプリの評価を求められることがある。
あれって結構便利ですね。

apple純正で簡単に追加できるので利用してみた。

参考サイト。
SKStoreReviewController まとめ – Qiita

基本的な使い方は、適当なタイミングで

SKStoreReviewController.requestReview()

これだけで良いらしい。

ただ、
・年に3回までしか表示されない。
・3回に満たないときは呼ばれたらほぼ必ず表示される。
らしい。

なので適当なタイミングで呼ばれるように考えてみた。

    // MARK: レビューのリクエスト
    func reviewRequest() {
        // NSUserDefaultsの取得
        let defaults = UserDefaults.standard
        defaults.register(defaults: ["reviewRequest" : 70]) //初期値
        
        //countToReviewの値に1たす。
        defaults.set((defaults.integer(forKey: "reviewRequest")) + 1, forKey: "reviewRequest")

        let count = Int(defaults.integer(forKey: "reviewRequest"))
        
        print("このページの表示 \(count)回目")
        if count >= 100 {
            SKStoreReviewController.requestReview()
            defaults.set(0, forKey: "reviewRequest")
        }
    }

100回呼ばれるごとにSKStoreReviewControllerを呼び出す。
但し、最初はしばらく使った30回目くらいでレビューをリクエストしたいので初期値を70にする。
これをviewDidLoadあたりに入れておけば、一日一回起動するなら年に3回程度になるかなという計算。

まあべんりだ。

【Swift4】【AdMob】【Stack View】広告を消したり表示したりする。

Stack Viewを使うと広告が表示されないときの処理が便利だった。
Stack Viewについては以前に書いたページを参照。
【Swift4】縦長のスクロール画面をscrollViewとstackViewを使って作る。
【Swift4】UITableViewの基本のき。

スクロールビューにスタックビューを入れていたり、高さの制限をかけていないビュー(テーブルビュー等)と一緒にスタックビューを使っていると、バナービューをisHiddenにすると綺麗にトルツメされるのですごく便利。

バナービューの状態の取得などについては下記サイトを参照。
バナー広告  |  iOS  |  Google Developers

GADBannerViewDelegateと、
bannerView.delegate = selfを、
設定しておけば広告リクエストの状態が受け取れます。
それを利用してバナービューの表示非表示を決めます。

先に、Storyboardでバナービューのishiddenにチェックを入れておくと広告を受け取った時点でバナービューが表示されます。

以下サンプルコード。

import UIKit
import Firebase

class ViewController: UIViewController, GADBannerViewDelegate {

    @IBOutlet weak var bannerView: GADBannerView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716" //テスト用ID
        bannerView.rootViewController = self
        bannerView.delegate = self
        bannerView.load(GADRequest())
    }
    
    /// Tells the delegate an ad request loaded an ad.
    func adViewDidReceiveAd(_ bannerView: GADBannerView) {
        print("こうこくをうけとった!")
        UIView.animate(withDuration: 0.25) { () -> Void in
            bannerView.isHidden = false
        }
    }
    
    /// Tells the delegate an ad request failed.
    func adView(_ bannerView: GADBannerView,
                didFailToReceiveAdWithError error: GADRequestError) {
        print("こうこくうけとりしっぱい: \(error.localizedDescription)")
        bannerView.isHidden = true
    }
}