CoreData many to many における、many の検索

CoreData を使い、野鳥観察記録帳のデータを管理。観察記録テーブルと野鳥一覧を many to many で連結。RDB の場合、

(1) 野鳥観察記録ー(N )観察した野鳥ー(1) 野鳥一覧

のように、テーブルを定義しますが、CoreData では many to many という指定ができるので、トランザクションテーブルである、観察した野鳥は作らなくていよい。あー便利・便利。

と、ここまでは良かったんだけど、野鳥観察記録一覧から、観察した野鳥の名前で検索するにはどうすればよいのか。つまり、あの珍しいジョウビを観察したのはどこだっけ?となってしまった場合、「ジョウビ」と入力したら、ジョウビタキが観察された記録を探して欲しいということ。

いろいろ調べたところ、SUBQUERY と ANY という指定ができるようで、

        NSPredicate* predicate =

         [NSPredicate predicateWithFormat:

          @"location CONTAINS[c] %@ OR (ANY toWildBird.jname CONTAINS[c] %@)",

          incSearchText, incSearchText];

 

こんな書き方が可能。ANY で指定している、toWildBird.jname 部分は、Relationship で定義した名前と N 側のフィールド名になる。Relationship 名の代わりにテーブルの名前にしてしまうとエラー発生(key path error)なので、すぐわかる。

many to many の指定は、RDB に慣れているとそんな指定はできないので初めよく分からなかったんだけど、追加、削除、検索がすごく簡単にできるので、理解できると、とても便利ですね。

 

フォアフット

フォアフットで走ると速く走れる(らしい)と聞いて、実践中。

初めは全然できなかったのだけど、階段を降りる時のように、着地する側の骨盤を下げ、逆に言うと、軸足の骨盤を上げることで着地しやすくなった。

問題はふくらはぎで、初めは疲労感と痛みで 10Km 走れず、体に悪いのではないかと思えたほどですが、3 ヶ月ぐらいでようやく 25Km ぐらいは走れるようになった。未だに、疲労するけど。

フォアフットの利点は未だによく分からない。明らかに違うのが、太ももの前面が全然痛くならないのと、明らかに太ももの裏側の筋肉を使って走っている。そのせいで、今までと比較すると、疲労感は少なく感じる。本などによく書いてある太ももの裏の筋肉を使った走りはどうやるのか疑問だったのだけど、こういうことかと、ようやくわかった。ま、ふくらはぎ疲労とのトレードオフなんだけれども・・・

太ももの前面とふくらはぎの疲労を比較すると、ふくらはぎの方が回復が早い気がするので、それはいいかも。

膝が痛くならないというのもよく見かけるのだけれど、初めから痛くなかったんでここはどうってことがないのだけれど、走った後に膝使ったなぁという感じは確かにしない。

今よく分からないのが、スピードを上げてフォアフットすると以前よりもかなりぎこちない感じ。短距離の走りならフォアフットでできるのだけれど、長距離のスピード走の時のフォームがしっくりこないし、実際速く走れていない感じがする。

また練習してみよう。

 

CoreData relationship, Many-To-Many (N 対 N)について

CoreData を使うと、One-To-Many (1 対 N)や Many-To-Many(N 対 N)を形容できるということで、いろいろ試してみた。

私はもともと RDB を扱っていたので、Many-To-Many の概念がよく分からない。RDB の場合、1 : N : 1 のようにすれば良いわけで、Many-To-Many はなんでそんなことすんのか、することのメリットはなんなのかがよく分からなかったのです。

結論からすると、Many-To-Many は使える。RDB では、1 : N : 1 の形は、1 をマスター、N をトランザクションと呼んでいる。Many-To-Many ではトランザクション系テーブルを作らなくてもよく、トランザクション系のテーブルはプログラマが明示しなくても CoreData が自動で作ってくれる。

さらに、今日のテストでわかったことは、Relationship は重複したレコードを自動で排除してくれる。理由は、Relationship は NSSet で定義されており、NSSet は元々要素の重複を許さない型だからだ。

このような仕組みが採られることが理解できるようになると、プログラムがずいぶん楽になる。以前、RDBトランザクション系のテーブルにレコードを追加する時、重複がないように追加する前にチェックしていたけれども、その必要はない。

コツのようなものはあり、重複しないようにするには、マスターのレコードをポインタで渡すこと。そうしないと、重複の判定がかからないので、いくらでも追加できてしまい、便利な機能を享受できない。

概念はこれぐらいで、今度具体的な方法を記載しよう・・・

 

R1 フーディとキャプリーンサーマルジップネックフーディの違い

冬のジョギングは寒いので、ウインドブレーカーの中に着るのにいいのはないものかと探していたところ、patagonia のキャプリーン 3 (以前はこう呼んでいたはず、いつのまにかキャプリーン4、サーマルと名称が変わった気がする・・・)が良さそうとのことで、数年前に購入。とても具合が良く、走り始めは寒くないし、走り出して暑かったらジッパーを開けて風通しをよくできるので愛用しています。

土日は連続してジョグするのですが、洗濯して乾かないときに、さてどうしたものかと、もう一着買おうかなと調べていたら、同じく patagonia で R1 というのがあり、評判がすごく良い。キャプリーンと形も素材もよく似ているのだけど、さあ、どちらを買おうか悩んだ末に、R1 を購入。

キャプリーンと R1 の違いは、キャプリーンの方が風を通しやすい素材で、内側のキャラメルブロックの目が荒い。どうせウインドブレーカーを上に羽織るので、風通しは実はどっちでも良い。汗の吸収と発散はキャプリーンの方が上。

あと、R1 を一番上に着て外出はありそうでも、キャプリーンを一番上で外出はないかなと。なんでかというと、下着っぽいので。実はどちらも自分的にはないことなんだけど書くだけ書きました。

どちらもフーディを買ってしまいましたが、ジップネックの方が、普段着として寒い日のインナーにできて使い勝手が良い気がしますが、いつもセールで買うので選択肢が限られてしまうのが難点かと。

ちなみにサイズですが、183cm, 67Kg ですが、どちらも M サイズでぴったりです。丈は十分ですね。

特徴がわかったところで、また数年後になろうかと思いますが、在庫が潤沢なうちに買うことにしよう。さて、今回買った R1 は何年着ることになるのやら・・・

Swallow tail vent foodie

ランニング用に TNF のスワローテイルフーディを愛用していたのだけど、長年の酷使に耐えきれず、ついにチャックが壊れてしまった・・・レースとかでも使っていたので、チャックの金属部分が汗で腐食して取れてしまった。これでもまだしめようと思えば閉められるけど、指が痛くなってしまう。

このウインドブレーカーは優れもので、裏地がイボイボしていて汗をかいてもさらっとしている。さらに、少しだけ汗を吸ってくれる生地のようで、ウインドブレーカーにしては割と汗の抜けが良い(と言っても、暑い日に着ると肘の部分に汗が溜まるけど、それはどんなウエアでも同じということで・・)。フードのところがポケットになっているので、折りたたんで収納できる仕組み。袋と違って、いつの間にかなくしてしまう心配がない。さらに、作り込みがすごく丁寧。ポケットの中にチャック付きのポケットがあり、家の鍵なんかを入れる時に安心。

もう、5 年ぐらい着ていたので壊れたことを機にそろそろいい加減買い換えようと、patagonia のフーディが評判良いので、セールに合わせて新調しようとしたら売り切れ・・・であれば、また同じスワローテイルにするかと物色していたら、スワローテイルベントフーディというのを発見。調べてみると、ベントの穴が随所に空いていて、汗の抜けがさらに良くなったようだ。ちょうど、安く買える店も見つけたので、買ってみました。

気に入っていたポケットの中のポケットは無く、フードの紐とツバもない・・・なんか作りが悪くならなかった?と思いつつも、肝心のベントはすごくいい感じ。腕、脇、背中にベントがある。今回、襟が良くなって、フードがあるのにスタンドカーラーにできる。フードの紐は無くなったけど、これはおしゃれでいいね。フード裏にある収納ポケットは健在。サイズも、前は売り切れで已む無く L を買ってやや小さかったので XL にして正解。ぴったり。まだ走っていないけど、快適そうですごく楽しみ。

self.property と _property の違い

objective-c でプログラムしていて、property の値をいじりたい時、self.property と _property どっちにすればいいのか、ふと悩んでしまいました。

実験した結果、self.property とすれば、setter が呼ばれました。ので、setter を呼びたい場合は、self.property にしたほうが良いと。

_property では setter が呼ばれません。

軽くハマりましたが、使い分けができるようになって良かったです。

NSPredicate で検索句を作る

バードウオッチングをして、フィールドノートを記録するためのアプリを作成中です。日本で観察できる野鳥名のマスタは日本野鳥の会から取ってこれたので Core Data に入れました。頭一文字を入力したら、候補の野鳥名が一覧で出てくるようにするにはどうするのか調べたところ、NSperdicate の出番だと。

predicateWithFormat メソッドを使用すると、完全一致で検索ができるようになったのですが、前方一致で検索する方法が分からない。さらに調べたところ、between, like, contains などが指r定できることがわかりました。何だか SQL っぽいですね。

画面から入力された文字の末に * をつけて検索したいところなのですが、うまくいかない。predicateWithFormat:"jname LIKE %@*", searchStrings と安易に指定してみたところエラー発生。

* を取って検索すると完全一致で検索だし、試しに contains を指定してみたところ、任意一致で検索する始末・・・、、ま、これはこれでいつか使えなくもないのでよいかもしれませんが。。。

試行錯誤の末、次のように、* を含む検索文字を作っておくことでうまくいきました。

    NSString* searchword = [NSString stringWithFormat:@"%@*", searchStrings];

    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"jname LIKE %@", searchword];

searchStrings は、このメソッドの引数。

なんかめんどくさいなぁ。

 

後日談ですが、さらに調べたところ、MATCHE という慣用句があり、LIKE の代わりにこれを指定すれば目的達成だと、めでたし、めでたし・・・