ヴェポライザーでシャグ:Domingo Menthol

C Vapor 2+ と HerbStick Relax を使っています。合うシャグがないかと思い色々試していますが、先日恵比寿に行った折に、昔ながらのタバコ屋がありシャグを物色。Domingo は吸ったことがないので買ってみました。

失敗しました・・・

どうやっても、ヴェポライザーでは楽しめません。加湿しないのが一番味わい深いように感じましたが、それでも軽い。キック感がない、全然ない。加湿するとマイルドになるけれども元々キック間のないところにマイルドになってどうすると。HerbStick Relax の底にティシュを詰め詰めキツキツにしてこれなら味出るだろと思ったけれども、改善なし。手強い。Choice に近いのかもしれない。あれも全然ダメだった。温度を上げると、お、いい感じかと思ったら、頭痛くなる味わい。もう、ダメだこれは。

しょうがないので、手巻きタバコとして使用することにしよう。はい、ローラーで巻き巻き。40g もあるので、消費するのが大変だ・・・ちなみに、Domingo とは、スペイン語で日曜日のこと。

 

今のところの、(オレオレ)シャグランキング(ヴェポライザー)

1. Colts Clear Menthol

2. Stanley Ice Mint

3. Che Menthol

×:domingo menthol

×:surfside

×:Choice

 

 

CoreData: 追加した object で、最近追加したものを上にするには・・・

CoreData に Orderd というチェックがあり、チェックしておくと detail の tableView で追加した順で並んで表示されるので便利。でも、detail の record は tableView で表示するのですが、record 数が多くなると、最近追加したものが上にある方が好ましいのは誰しも思うところ。

これを実現するにはどうするのかよく分からなかったんですが、ようやく分かりました。結論は、add ではなくて insert を使えということになります。こんな感じ。

変更前:        [_detailItem addToEntityObject:newEntity];

変更後:        [_detailItem insertObject:newEntity inToEntityAtIndex:0];

ポイントは、add...  の場合、指定する必要のなかった index を指定する必要があります。一番上にしたいなら、常に index 0 を指定することになります。

ちなみに、in....AtIndex の ... 部分は relations で命名したものが使われます。ので、途中まで入力して tab キーを押して補完してもらうのがよいと思います。

って、これ、初めは表示するときにどうにかするんじゃないかと思って色々試行錯誤したんだけど上手くいかなくて、保存するときに method が用意されている、という顛末だったんで、調べるのに結構時間かかった・・・

 

CoreData: Master-Detail の detail 処理について

CoreData を使用するテンプレートで Master-Detail があり、とっかかりは重宝するのですが、立て込んだことをしようとすると色々わからないことが多い。

今日分かったのは、Detail の record 編集について。

Master から Detail の ViewController に移動しますが、そこはつまり Master の詳細画面な訳で、Detail に record を追加したり、あるいは編集したいという時のために Detail 用の ViewController が必要になります。言ってみれば Detail-Detail ということになるでしょうか。テンプレートの名称からして誤解が生まれそうなんですが、Master の 1 record を編集するための名称として Detail としている訳で、1 : N の N レコード一つ一つを編集する画面ではないということになります。

そんな構造が分かっているとしても、Detail に設置した tableView のレコードを追加する部分までは、Master-Detail のテンプレートからそれなりに応用が効くと思いますが、追加済みの N レコードを編集するにはどうすればよいか、はたと悩んでしまいました。こう言ったことに言及している記事がないので、オレオレですが書いておこうと思います。

まず、tableView に表示されているレコードが選択された時に呼ばれる delegate method はこれ:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

この method 内で、選択された cell をグローバル変数に入れておきます。次に、

performSegueWithIdentifier

で、強制的に prepareForSegue を呼びます。prepareForSegue では、遷移先の Class の property に値をセットしてやります。こんな感じですかね。

    InputDetail* controller = (InputDetail *)[segue destinationViewController];

    [controller setDetailDetail:selectedCell];

書いていませんでしたが、遷移先にはあらかじめ対応する property を設定しておく必要があります。上記の例では detailDetail という property になります(property を新設すると勝手に method が作られている、、というか、もともと Objective-C で property をそう定義してあります)。ところで、prepareForSegue で遷移するには理由があり、遷移先の ViewController (のポインタ)を取り出し易いのです。キャストしないと警告が出る点が嫌なんですが、他に書き方がわからないのと、キャストする都合、汎用的な書き方じゃないよね(他のプログラムにそのまま使い回せないね)というのが難点でしょうか。

遷移先では、property detailDetail に値があるかどうかで挙動を変えるようにします。書き方は、DetailViewController の template のが参考になります。

 最後に、DetailDetail から Detail に戻ってきたときに呼ばれる method は次の通り。

- (IBAction) firstViewReturnActionForSegue:(UIStoryboardSegue *)segue

このメソッドでは、グローバル変数にセットした値をクリアしておく必要があります。なぜなら、record を追加しようとしているときも、選択したときも結局は prepareForSegue が呼ばれるので、追加したときもセルを選択した時のような挙動になるためです。

という訳で、できたのでよかったんですが、こういう解説があまりないのが CoreData の辛いところでしょうか・・・

CoreData Orded の処理

CoreData をいじっていたら、Orderd というチェックボックスがあることに気づいた。

名前からして、n 側の並び順を維持してくれるんじゃないかと期待が高まります。早速使ってみたら error 発生。なんで?

通常、n の record を取り出すには、array に突っ込みます。こんな感じで。

        NSArray* relatedRecords = [_detailItem.toRelateMany allObjects];

 

でも、並び順を維持するには、array ではダメで、NSOrderdSet を使う必要があるのだ。

        NSOrderedSet* relatedRecords = [[NSMutableOrderedSet alloc]initWithOrderedSet:_detailItem.toRelateMany];

 

それはよいのですが、class が違うので中身を取り出す時の method も、違う点を見逃してはならない。array の時は allObjects、orderedSet の時は initWithOrderedSet: となる。

ふぅぅ。

Sandman と K2apartment で買物

今日は休みを取ったので、遅ればせながら冬の服を買いに。丁度、Soundman のサンプルセール初日だったのではるばる恵比寿まで電車で移動。

サンプルセールとはなんだ?という話ですが、試作品や貸し出し見本のように市場に出ていないなものを格安で売る機会なんですね。Soundman のアトリエで開催なのですが、果たして人が来るのかなぁ、一人だったら嫌だなぁと思っていたのですが、行ってみたら結構人来てました。人多くて試着がやりにくいほど。

Birmingham と Marcy があるといいなと思っていたのですが、全般的にサイズ 38 が中心でちょっと自分には小さいなぁと。モールスキンの黒は 40 が売っていたのでこちらを購入。

その後、以前から気になっていたつくばの K2 に行ってシャツ買いました。ここは取り扱っている服のセンスがすごいオシャレ。また今度行ってこよ。

 

CoreData: Illegal attempt to establish a relationship 'hoge' between objects in different contexts の対処

Master-Detail で CoreData を使っていて遭遇したエラー。

予め書いておくと、context を作るときに、

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

のようにしておけば、特段の問題はないのですが、そうしなかったとき、エラーに書いてある通りで、pointer 的には別のものを指定している訳で、エラーになってしまうのだということが分かりました、分かってしまえばどうってことないのですが、分かるまでが大変で・・・(ってか、エラーよく読めと)。

上記の指定の嫌なところが、わざわざキャストしてやる必要があるところで、そうしないと warning が出てしまいますから已むを得ないのですが、ちょっと面倒で、でも、CoreData としては singlton 扱いして欲しいでしょうからしょうがないのです。

ちなみに、このエラーですが、モデルを作成するところで、inverse の指定をしなければ回避できてしまいます。でも、よくよく調べて見ると Apple 的には inverse は普通指定しろよ的な扱いなんですね。エラー回避するために、inverse の指定やめようかなとも思いましたが、それでは進歩が無いと思い、色々調べてエラーの原因がわかって、将来的にはよかったです。

 

nib but the view outlet was not set. の解決方法

Master-Detail アプリケーションで、Detail にさらに tableView を配置し customCell を設定しようとするとエラー発生。

tableView のデリゲートは設定済。必須のメソッドも実装済。これね、すごい根深い問題がありますね。ViewController のファイル名と、xib のファイル名を区別しないとうまくいかないと。詳しくは以下を参照:

これね、わかんないよ普通。

 

うまいやり方は、次の通り。

  • detail 内の tableViewController はわざわざ新設せず、UITableViewController のインスタンスとして生成すれば delegate method を使う都合もあり、便利
  • 必須の method は 以下の 2 つ。
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

結局、table cell はうまく設定していたのに、その後 tableViewController を新設しようとして名前問題が発生してしまった、ということになります。