swift テーブル1画面2つ上下表示

それぞれのテーブルを判別できるようにしておく必要がある。 そのためクラスを2つ作成した。同じファイル内に(継承はしていない) まずアクセスするために下のテーブル(別クラス)のインスタンス生成

上のテーブルのクラス

class Dic_iphone: UIViewController, UITableViewDelegate, UITableViewDataSource,UISearchBarDelegate{
 //下のテーブルのクラスのインスタンス
    var table_down = Table_down()
   //テーブルの名前を分けて接続、
   //上のテーブル
    @IBOutlet weak var listTable: UITableView!
    //下のテーブル
    @IBOutlet weak var detailTable: UITableView!


//viewDidloadにデリゲート宣言

 override func viewDidLoad() {
        super.viewDidLoad()
        //上のテーブル
        listTable.delegate = self
        listTable.dataSource = self

         //下のテーブルのデリゲートここがポイントといえばポイント
        detailTable.delegate = table_down
        detailTable.dataSource = table_down

下のテーブルクラス

class Table_down :NSObject, UITableViewDelegate, UITableViewDataSource{
通常のデリゲートメソッドを記載
接続は上のテーブルのクラスにて行う。
       //セルに表示
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        //datasource func
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return datDics_down.count
        }
        //セルの内容表示
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! DetailCustomCell

この下のテーブルを扱うクラスには特別な処理はなにもない。

以上

swift CoreData 保存 カメラで取得した画像

まずカメラの利用には

UIImagePickerController

が必要。何をするかというとアップルのサイトより

ユーザーのメディアライブラリから画像を撮影し、ムービーを記録し、アイテムを選択するためのシステムインタフェースを管理するビューコントローラ。
のは、(メディアキャプチャをサポートするデバイス上で)新しい画像やムービーを撮るためのユーザインタフェースを提供します。

ふむふむ、大切ですね。カメラや、動画、写真へのアクセスする際にはこのメッソドを利用します。

クラスはUINavigationControllerDelegateとUIImagePickerControllerDelegateを継承します。

UIViewController , UINavigationControllerDelegate, UIImagePickerControllerDelegate {
sourceTypeUIImagePickerController.SourceType.camera

//関数定義をみるとゲッタセッタをセットするとあります。
var sourceType: UIImagePickerController.SourceType { get set }

UIImagePickerController.SourceType には3つある

case photoLibrary //iphoneの写真から取り込む

case camera //カメラから取り込む

case savedPhotoAlubm //デバイスがカメラ持っていない時のフォトアルバム

表示するときはpresentメソッドを利用する これはuiviewControllerのインスタンスメソッド

func present(_ viewControllerToPresent: UIViewController, 
    animated flag: Bool, 
    completion: (() -> Void)? = nil)

ここではimagePickerControllerを指定しているが、他のクラスも指定できます

// (1)撮影が終わったときに呼ばれるdelegateメソッド

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        // (2)撮影した写真を、配置したpictureImageに渡す
        pictureImage.image = info[UIImagePickerControllerOriginalImage] as? UIImage

        // (3)モーダルビューを閉じる
        dismiss(animated: true, completion: nil)
    }
}

このデリゲートメソッドはinfo: [String : Any])にカメラで撮影された情報が格納されているとある。 どういう意味かというと、関数定義では

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;

// info dictionary keys

public let UIImagePickerControllerOriginalImage: String // a UIImage

フレームワークの中では、辞書型 string とidで持っている

info: [String : Any]

のなかで辞書型のデータを渡している。辞書型とはkeyと値のペアで情報を持つ、配列だと思えば良い。 Rubyのハッシュですね。 辞書にアクセスるるのはkeyでアクセスする。 定義を見ると

UIImagePickerControllerOriginalImage: String 

とある。つまり文字列のkeyを渡しているのだ。値は、iphoneのカメラで撮られたデータが入っている。そこから先はは知らなくていい。 目的達成のために、写真が利用できればいいのだ。

あとは保存処理。上記デリゲートメソッドの中の

pictureImage.image = info[UIImagePickerControllerOriginalImage] as? UIImageのあとに書いていこう

        //jpegデータに変換するメソッド 第1引数は画像、第二引数は解像度
        let img = UIImageJPEGRepresentation(pictureImage.image!, 1)
        //save関数に保存は委ねる
        saveData(imageData: img!)

    func saveData(imageData:Data){
       //persistcontainerを作る。入れ物を用意しておく
        let appdelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appdelegate.persistentContainer.viewContext

        //ここポイントです。Photoテーブルの型でpersistcontainerでもってオブジェクトをつくる.
        let photo_core = Photo(context: context)  

        //そうするとphotoテーブルのプロパティ(カラム)にアクセスできる。
        photo_core.pic = imageData

        //エラー処理 後述します。
        do{
            try context.save()
        } catch    {
         print(error)
            }
            
    }

Photoはcoredataのテーブルのことです。

ちなみにcoredataのテーブルのカラムの型は BinaryData型になります。 f:id:happy_teeth_ago:20180628003710p:plain

エラー処理について

do ~ catch文
基本形
do {
     try  エラーが予想される処理(throwキーワードが指定された処理を呼び出す場合)
    
 
    }catch{
     エラーが 発生したときの処理(普通print(error)を書きます。
}

ただ、CoreDataの中に、バイナリで持つのはおすすめしません。 画像データは大きいので、DBが遅くなります。 String型で参照を持つほうがいいです。 そのあたりは、また記載していきます。

正規表現まとめ Ruby

正規表現について まず、正規表現とはなんぞや?ということから

あいまいな文字列パターンを正しく認識するためのしくみです。

WEBの入力で、メールアドレスを入力したりしますね。 そのときにメールアドレス以外のものが入るとメールアドレスが違っています。 などと表示されますね。 それは、正規表現を利用して、プログラムが判断しているわけです。 では正規表現の作業のながれをまとめます。

1-正規表現の書式を決める

2-それがデータと一致するか?

部分一致か全文一致か

3-その時の処理

合致したときや、そうでないときの処理を書く。

正規表現の書き方は
このサイトが一番いい developer.mozilla.org

例えばRubyで、ipアドレスが正しいか?だとこのように書く。

reg = Regexp.new("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$")

まずRegexp関数(レッグ)と呼んでいる。 でオブジェクト作ります。 その時

正規表現の始まりを表す  ^ と終わりを表す $

がとても大切。

[0-9]は0〜9の文字列が入りますよということ。
次の{1,3}は最低1回は0-9の文字があります。最高は3回入りますよ。ということです。
{ }は何回繰り返すかを表現します。
[ ]は集合。 [0-9]なら 0から9までの数字
[a-z]はa~zまでのアルファベット
便利なのは [\w] アンダースコアを含む、どの英語、数字にもマッチします。
str = abc
str =~ reg 

これはabcは数字でないので当然 falseが返却されます。
Rubyは =~ の演算子で正規表現のパターンマッチを評価します。
マッチしたときはマッチした部分の位置を整数で返しますマッチしなかったらnilを返します。

swiftの場合

    let pattern = "^[\\d]+$"
        guard let regex = try? NSRegularExpression(pattern: pattern) else { return false }
        let matches = regex.matches(in: self, range: NSRange(location: 0, length: length))
       

まずpatternを決めていますね。 それからguard文でnilのときにreturnで処理を抜けるようにしています。

NSRegularExpression関数を利用します。 正規表現を利用するクラスです。

Rails postgresのコマンド、設定等

AWSでポスグレのDBを利用しないといけなくなりました。 herokuへデプロイするためです。

railsのdatabase.ymlの設定にDBを作らないといけないです。 ポスグレはインストールされているとしてその後の作業を記載します。 インストールについては、別途まとめる予定です。

まずポスグレの起動

service postgresql start

Rails デフォルトのSQLiteはファイルなので、起動しなくてよい。
しかし大規模のデータ処理には向かない。
よって毎回ポスグレを立ち上げる必要があります。
もちろんdevelopmentをSQLiteに設定する方法もあります。
しかし、一度ポスグレを利用すると
inetタイプをテーブルに保持する。そのためにSQLiteへの変更はエラーになる。
はじめからDevelopmentはSQLiteで作っておくのが望ましい。
ついでにそのあたりの設定も書きます。

config>database.yml

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

test:
  <<: *default
  database: db/test.sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/test.sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  
production:
  adapter: postgresql
  encoding: utf8
  database: [app_name]_production
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  url: <%= ENV['DATABASE_URL'] %>

gemは

gem 'sqlite3', group: [:development,:test]
gem 'pg','>= 0.18', '< 2.0', group: [:production] 

デプロイ時だけポスグレを利用する設定にしておきます。
'pg'のバージョンは利用できるものに変更してくださいね。

先程の話ですが、ポスグレでDB作ってあとにSQLiteに変更すると発生する問題は、inetのことです。
inetとは
inetタイプは、IPv4またはIPv6ホストアドレス、およびオプションでそのサブネットをすべて1つのフィールドに保持します。 勝手に作らているのでどうしようもないです。
参考サイト stackoverflow.com

まずポストグレスにログインしないといけません。 ポスグレをインストールすると、デフォルトでpostgresというユーザーが作られています。 UNIXにもユーザーがいて、ポストグレスにもユーザーがいる。
このあたりが、初心者には戸惑うところではないかと思います。 ポスグレもDBなので、多くのユーザーがアクセスします。しかもリモート接続もします。 よって権限をきちんと割り振っておかないと大変なことになります。
ロリポップなどの格安サーバーで、ワードプレスインストールする際に、DBを作りますね。あれはポストグレスのようなDBが、ユーザーと権限をきちんと管理しているので、一人が何個もワードプレスインストールできたり、他のユーザーと混ざらないようになっています。DB偉いですね! 話それましたが、

$ sudo -u postgres psql

これでpostgresユーザーになっています。ついでに psqlという、ポストグレスにログインするコマンドを実行しています。

f:id:happy_teeth_ago:20180626111947p:plain

この画面ではまずpostgresユーザーになって、それからpsqlを実行しています。 それから

postgres=#この行がSQL文を実行するところ

SELECT * FROM pg_shadow;

これで全ユーザーを確認できます。最後のセミコロン忘れないように! まずポストグレスのユーザーを作成しないといけない。 ロールと言うらしいですね。

create role [user_name] with createdb password='[passwordを入れましょう]';

このロールはテーブルも作成できます。ロール作るときにも権限を付与しないといけないので、普通に作るだけだとテーブル作れないので注意が必要です。 テーブル作成して、ロールも作成したら

\q

で抜けます。 その下の階層 bash-4.2$というところで、ユーザーを確認したり、テーブルを確認したりします。 2段階になっているのでこれも初心者の戸惑うところかと、、

psql -l

で全テーブルを表示できます。 psqlコマンドですね。

bash-4.2$を抜けるときは

exit

でし。 これでよかったかな? これであっているのか分からないので何か気づいたらコメントお願いします。

SWIFT 電話帳読み込み-実装コード1

開発検証環境:Xcode Ver9.4.1 動作検証OS:iOS11.0 言語:swift3 iOSの標準アプリ「連絡先」に登録されている連絡先データを取得する方法のまとめです。 なお、忘備録的に書いていますので、なぜそうするのかについて主に記載していく予定です。 連絡先から取り込んだデータはたいていDBに格納すると思います。それでこのアプリの中のPersonData型として取り込みます。

①Contacts.frameworkをリンク・インポート  連絡帳からデータを取得するにはContacts.frameworkが必要であるので

②連絡先のピッカーを管理するクラスを利用 CNContactPickerViewController

   // MARK: CNContactPickerDelegate methods
    func contactPicker(
        _ picker: CNContactPickerViewController,
        didSelect contacts: [CNContact]) {

// CNContact ピッカービューコントローラ
//このクラスは、連絡先のピッカービューを管理するコントローラオブジェクトを作成します。
このクラスを使用すると、連絡先ビューコントローラ()に表示されている連絡先のリストから1つ以上の連絡先(またはそのプロパティ)を選択できます。
ピッカーは、連絡先の単一選択と複数選択をサポートします。
2つ目の引数がcontacts: [CNContact] となっているのは当然、ユーザーがいくつか連絡帳から選択するので配列で渡しています。

// CNContactPikerViewController が[Done]で終了した時
        // 選択項目の有無によらず呼ばれる
        if contacts.count == 0 {
            return
}

//何も選択せずにユーザーがDoneを押したときの処理。 //このようにnilが発生する可能性はすべて潰さないといけません。

        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
      return
        }

// 発生することは無いAppDelegateクラスがないことは考えられないので、当たり前といえば当たり前。 ちなみにAppDelegateクラスはC言語のmain関数のようなもの。 //これはcoreDataの保存処理。 CoredataはAPPDelegateにあるpersisitconttainerにアクセスして保存処理をします。 f:id:happy_teeth_ago:20180625221622p:plain 参考サイト ここのサイトの説明はとてもわかりやすいです。

qiita.com

//guard節です。Guardは条件が偽のときに{}ないの文を処理します。if文と逆です。そして{}の処理を抜けるためにreturnが必要です。なので記載しています。

        let context:NSManagedObjectContext = appDelegate.persistentContainer.viewContext
        //保存する入れ物を準備
        var freeDatPerson: DatPerson?
//このアプリで利用する型のインスタンスを宣言
//配列からとりだしてループ回します。
        for contact in contacts {
            // DatPerson を取得し id を割り当てる。直前が未登録DatPersonならそれを流用する。
            let datPerson: DatPerson
            if freeDatPerson == nil {
         
                datPerson = DatPerson.newFormalOne()
                freeDatPerson = datPerson
        
       
            } else {
                datPerson = freeDatPerson!
            }
2)につづく

newFormalOne()は何をしているかというと
別関数を呼び出しこの関数は下記。
staticが使われている。staticはどんな時に使うかと言うと、ざっくり
1)生成などのインスタンス変数に依存しない処理
オブジェクトを複数作る必要性のなく、いろいろなところからアクセスされるような場合?
例えば、定数クラス。
2)自分でオブジェクトを生成しなくても、参照出来る点
例えば、オブジェクトを生成する意味がない定数クラスを毎回生成してからじゃないと定数を取得出来ないというようなことがなくなる。
以下は別クラスのfunc

    static func newFormalOne() -> DatPerson {
        let dat = newOneWithId()
        dat.fdate = NSDate()
        dat.lastMeeting = dat.fdate
        dat.name = dat.defaultName
        let meeting = DatMeeting.newOneWithId(dat)
        meeting.date = dat.fdate
        return dat
    }

ちゃんと作ってますね。 newOneWithId()は何をしているかというと これ 別関数です。 新しくオブジェクト作ってますね。

   /// id 割り当て済みの新規インスタンスを返す
    static func newOneWithId() -> DatPerson {
        let dat = DatPerson(context: Contract.managedObjectContext)
        Contract.makeStringPropertyEmpty(dat)
        dat.id = numberIdOfNewEntity(Contract.entityNameDatPerson)
        return dat
    }

どんどん行きます。Contract.managedObjectContextは
頻繁に使うものは関数化しているだけの話。
特にCoreDataは同じことを何度も書かないといけないので、、、
保存領域を用意しているだけですね。

    /// アプリが使用してる NamagedObjectContext
    static var managedObjectContext:NSManagedObjectContext {
        return persistentContainer.viewContext
    }

numberIdOfNewEntity関数は

/// id列を持つエンティティーの新レコード用に id番号を発行する(アプリ本体用)
fileprivate func numberIdOfNewEntity(
    _ entitiyName: String,
    datPerson: DatPerson? = nil ) -> Int64 {
    return numberIdOfNewEntity(
        Contract.managedObjectContext,
        entitiyName: entitiyName,
        datPerson: datPerson)
}
//ここから2)
            // 姓名,セイメイ,会社:全て空の時は DatPerson には登録しない
            datPerson.name = CNContactFormatter.string(from: contact, style: .fullName)
            datPerson.kana = CNContactFormatter.string(from: contact, style: .phoneticFullName)
            datPerson.company = contact.organizationName
            if (datPerson.name ?? "").isEmpty &&
                (datPerson.kana ?? "").isEmpty &&
                (datPerson.company ?? "").isEmpty {
                continue
            }
            // 住所,電話番号,email:登録順に複数(Home,Work,..等)存在するが
            // 最初(先頭)に登録されたものを採用する。
            if contact.postalAddresses.count > 0 {
                let address = contact.postalAddresses[0].value
                datPerson.jusho = CNPostalAddressFormatter.string(from: address, style: .mailingAddress)
                // ※ style:には何故か mailingAddress を設定する慣わしのようである
            }
            if contact.phoneNumbers.count > 0 {
                datPerson.tel = contact.phoneNumbers[0].value.stringValue
            }
            if contact.emailAddresses.count > 0 {
                datPerson.email = contact.emailAddresses[0].value as String
            }
            print("ContactsImporter.contactPicker() id:\(datPerson.id), name:\(datPerson.name ?? "--")")
            do {
                try context.save()
                freeDatPerson = nil
            } catch {
                // 次の datPerson 登録が成功する事は考えられない
                // したがって、失敗したら中止とする
                print(error)
                break
            }
        }
        // save()中止した DatPerson を返却する
        if freeDatPerson != nil {
            context.delete(freeDatPerson!)
        }
    }

以上

Ruby フォーマット文字列について

2.345などの少数が出た場合文字の表示を整えたい場合がある。 その場合に利用するのが、フォーマット文字列 例えば 1.2を 1.200と表示させたい場合以下のように記載する。

Rubyの場合

sprintf('%.3f', 1.2)

#=> "1.200" と表示されます。

このsprintfというメソッドで整えます。 また%は指示子といって.3は小数点以下3桁まで表示しましょうねということ。
第一引数の小数点の右の数字は小数点以下は3桁まで表示しましょうねという意味。 0.3ではないので注意。
そして、第二引数の値 1.2 の表示を整えています。

rubyにはフォーマット文字列 % というのもあります。 基本形はこれ

str % 引数

となっています。
左辺の文字列strを% の右辺の引数の値を表現します。


'%.3f' % 1.2
#=> "1.200"と表示されます。

この文法は

%fはfloatの略、つまり少数ですね。
%dだと10進数の普通の数字となります。
%oだと、8進数で出力となります。
%s だと文字列を出力します。
%gは実数を最適な形で出力します。
では

'%8.3f' %1.2

の8は何かと言うと[全体の文字の幅]です。 指定しなくてもいいし、指定してもいい。 桁数の前に0詰めするとわかりやすいです。

'%08.3f' % 1.2

これは  
0001.200 と表示されます。

7という数字を007と表示したい場合を考えてみましょう。前に0をつけるのですね。 まず7は10進数の数字よって d を選択。 こうなります。

num = 7 
"%03d" % num  

#=> 003 と表示
numという変数を整えて表示してくれます。フォーマットは %03d です。
#文字列を10進数3桁、ただし前には0をつけて表示してねという意味です。222とか3桁の数字の場合前に0は付きません。

Swiftの場合

print(String(format: "%.3f", 1.2)

#=>1.200と表示される。

String型に型変換するときに formatで整えるのですね。

SWIFT Storyboardのsegueで遷移先に値を渡す(テーブルで選択した値)

segueで値を引きわたす。モデルで。 まずテーブルのセルが選択されたときの処理は、このメソッドデリゲートメソッドが呼ばれます。

送付元のクラスのテーブルで表示されている、DBの値をモデルごと渡す

送付先のクラスで、表示します。

送付元のクラスでの実装

まず送付元のクラス
  // メンバ変数 送付するモデル
    var send_person:Person?  //PersonはCoreDataのテーブル テーブルも型になる。

   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //選択行のpersonsを取得して詰め込み
        send_person = persons[indexPath.row]
        performSegue(withIdentifier: "detailSegue", sender: send_person)
    }

セル選択行をsend_personに詰め込みます。 それをperformSegue実行時に、senderで渡します。 ちなみにpersons[indexPath.row]で選択セルのデータが取得できますね。 配列に詰め込まれているのが、ループ処理みたいにされて、テーブルに表示されているわけですから、、、

    //モデルまるごと送っています。
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "detailSegue"{
            let subView = segue.destination as! detailViewController
            subView.person = send_person!
        }
    }

"detailSegue"はStoryBoadで画面を結んでいる線のプロパティに値を設定しておく必要があります。 f:id:happy_teeth_ago:20180623022939p:plain

送付先のクラスの実装

subView.personは当然、送付先クラスで宣言しておかないといけませんね。 ここでは、var person = Person()になります モデルごと送ると、遷移先でデータ表示するときが楽ですね。

   //受け取り用のインスタンス
    var person = Person()

   override func viewDidLoad() {
        super.viewDidLoad()
        
        person_name.text = person.name
        person_reading.text = person.reading
        person_birthday.text = person.birthday
        person_dead_day.text = person.deadday
  }

モデルでpersonごと渡しているのでモデルのプロパティにアクセスして、詰め込むだけです。 ここではpersonというモデルを渡しているということです。 わかりにくい点や間違いがありましたら教えてください。