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 の代わりにこれを指定すれば目的達成だと、めでたし、めでたし・・・

 

AppDelegate を他のクラスで使う

AppDelegate とは何だろう。delegate とどう違うのか。

私も未だ明快にわかっていないのですが、AppDelegate は、Application 全体を通じて共有するようなオブジェクトを定義しておいて、必要に応じて参照・更新するような使い方をするようです。言ってみれば、昔のグローバル変数にすごく似ているのかなと。

AppDelegate の場合、Application を通じて参照できるため、AppDelegate というクラスをわざわざ定義してインスタンス化したオブジェクト参照するという手の込んだ概念となっていますが、グローバル変数だと考えた方が遠回りでもないし、理解が早い。

オブジェクト指向では忌み嫌われるグローバル変数の概念ですが、例えばゲームのスコアのような全体を通じて参照・更新するような性質のものの扱いには、確かに便利な概念でしょう。

目下、CoreDate を使っていて、アプリケーションの随所で参照するマスターデータがある場合、AppDelegate で managedObjectContext を生成しておいて、他のクラスで必要に応じて参照・更新できると、多分、メモリの節約にもなるし code も少なくて済むでしょう。

そんな訳で AppDelegate を使おうとすると、素ではすごくめんどくさい。

NSManagedObjectContext* mg = [(AppDelegate *)[[UIApplication sharedApplication]delegate];

とした上で、

NSEntityDescription* entity = [NSEntityDescription entityForName:@"someEntity"

                                              inManagedObjectContext:mg];

などとする。

何がめんどくさいかというと、初めの (AppDelegate*)[UIApplication... の部分で、キャストですか?、使うたびに毎回ですか?、何ですかそれ? みたいな感じになる訳です。

なので、例えば、viewDidLoad メソッド辺りに、

appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];

としておくと、以降は、appDelegate.hogehoge のように、いつもの property のように使用できて便利だなと。

もちろん、クラスの頭で

Appdelegate* appDelegate;

と宣言することも忘れてはならない。

 

愛宕吾国ハイキング縦走コース

今年はトレイルの大会に出なかったので、年末の三連休に自主練することにしました。茨城方面の山でどこか良いところはないかと探してみたところ、3つほど候補があり、筑波連山縦走も考えたのですが総距離 37 Km と、あまりにも長く、自信がないので、愛宕山ー難台山ー吾国山の縦走コースにしました。これなら距離も17Km 程度と、難なく行けそう。

高尾山から陣馬山の往復縦走は以前何度か走ったことがあるのだけれど、今回のは常磐線岩間駅から水戸線福原駅までの one way。高尾山の場合、駅で着替えてコインロッカーに預けておけるのだけど、今回はそうはいかない。荷物はできるだけ軽く済むよう厳選して、着替えのウインドブレーカーとジオラインを持っていくことに。その他、飲み物 1L と財布などを入れたらリュックはもう一杯。

当日は 6 時前に家を出て、岩間駅に着いたのは 7:30 頃。前日、台風?ではないと思いますが、やけに暖かくて、その気温を引きずり今日も暖かい。キャプリーンを着ていたら暑い。山中、モヤが多くて景色が見えない。中盤快晴となり景色を満喫できたのはよかった。ゴールの福原駅に着いたのは 11 時少し前だったので、3 時間半ぐらいかかったことになる。道中、道はよく整備されていて、ところどころ看板も立っているので迷うところはあまりありませんでした。

そんな中、次回に備えて、2 箇所だけ間違いそうなところを書いておこう。愛宕神社から先は、神社の階段を降りて手を洗うところの横にある階段を降りる。せっかく苦労して登った分ほとんどを降りてしまうことになるので、もったいないのと本当にこれで良いのか不安になりますが、それで正解。

もう一つは、吾国山を降りて福原駅までの道。登山道入り口から先に、ところどころ看板が立っているのでそれに従って道を採ることになりますが、あぜ道のようなところはほとんど迷わなくて、一般道に出てからがわかりにくい。駐在所付近まで行ってしまったらそれは行き過ぎ。遥か彼方に見えるのは実は水戸線で、そちらの方面に左折した方が良い。今回は看板を lost したらしく(ってか、看板立ってた?)なんかおかしいと思って iPhone の地図で確認したら行き過ぎに気づいてルートを修正。最後の最後で lost するとガックリ感が大きい。

一方、トレイルのコースはほとんどがダブルトラックで道迷いの心配はない。でも、このコース、アップダウンがきつすぎて、登りはほとんど走れなかった・・・。また、前日の雨で滑りやすくなっているところがあり、傾斜のきついところでは滑って登れないところが 2 箇所だけあり、難儀しました。以前、岩間のトレイル大会に出た時も傾斜きついなと思ったのだけど、ハイキングコースと甘く見るとかなり痛い目に合いそう。

走った後は、いこいの家はなさとで風呂と食事しました。アルコールも置いてあって、つい、ハイボールを飲んでしまいました。もう少し近いと良いのだけど、クールダウンと言い聞かせて歩きました。宍戸駅前の踏切がちょうど工事で通れなくなっていたのでかなり迂回したので、2Km 以上あると思います。

また時間を見つけて challenge してみよう。