Vagrant + VirtualBox + NetBeans + PHP + MySQLの環境作りに悪戦苦闘

今回はタグがてんこ盛り。
PHP自体すこし齧ってSmartyでブログシステムを制作した覚えが…
その時はXamppを使用してローカル環境を整えたんですが今回は少し高度(ワタシ目線)になった環境で行こうかと思い壮絶に迷走したわけですね。
Macでの環境構築です。
Vagrantは開発用の仮想環境を構築し、Virtualboxは仮想のOS環境を構築することが出来ます。
この2個を合わせると開発者が皆同じOS環境で開発ができハッピーなのです。
まぁこんな説明はとうの昔知ってるよ!ところなんですがね…
まずVirtualboxDownloads – Oracle VM VirtualBoxでダウンロードしてきてインストール!
ここでの作業は一旦終了で次にVagrandをDownload - Vagrant by HashiCorpでダウンロードしこれまたインストール!
ここで壮絶に勘違いし$を1個多く打ち込みnot foundの雨あられ…
普段からコマンド使っていない生物なので意味も分からずに$を打ち込み盛大に自爆。
vagrand -vでバージョン確認しOKなら次にA list of base boxes for Vagrant - Vagrantbox.esでvagrandをVirtualboxで構築するためのツールをダウンロードしてきます。開発したい環境に合わせて取得して下さい。
ここから後はどこぞのサイトを参考にして下さい。(遠い目)
懇切丁寧に説明されているサイトです。
techacademy.jp
久しぶりのPHPだぜ…覚えてるかなとか思ってた時期がry

コマンドが変わっていて大混乱…
CentOSでやってたんですけどchkconfigやらserviceがsystemctlに機能が統合されていて、コマンドを打ち込んでも反応を返してくれない等の素人いじめが発生。redirectとか言われてもさ…一応ステータスが変わっているから効いてる部分も
ファイアーウォールの設定を変える為に

sudo service iptables stop

そしてニッコリ返される

No such file or directory(そんなもんネーヨ!)

どやらインストールしなきゃ無いらしいですね…トボトボ
そんなこんなでやっと設定完了。

一息ついて次にMySQL入れなきゃ!
調べて、

sudo yum install mysql-server

どこ調べてんだよ!そんなもんネーヨ!

えっ?

sudo yum install mysql

ほいインストールするよーーー
mariadb
mariadb...

えっ?
正解は、

消して
yum remove mysql*
[http://dev.mysql.com/downloads/repo/yum/:title=MySQL 公式の yum リポジトリ]をインストール
yum -y install http://dev.mysql.com/get/{最新のMySQL}

iOSでローカルのtextファイルを取得する。

やりたかったことは説明などのテキストをWebViewを使用してHTMLで表示したかったのと、
説明の記述はテキストファイルで保持し説明毎にテキストファイルを読み込むという流れです。
多言語対応にしようとするとLocalizable.stringsでは複雑化し面倒だなーって思ったわけですよ。
javascriptでFile APIを使ってバンドルのデータを読み込もうとしてもエラーが起きて計画が頓挫…

じゃあパスを渡さずにテキストを渡せば良いじゃないかと囁かれて、実践。
読み込まない…
長いコードがダメなのか?短いコードなら成功するんですけどね。
ふと…改行コードどうしてるんだろって思い、1行に纏めてみると成功…あれま。

これによって、[[NSLocale currentLocale] localeIdentifier][[NSLocale preferredLanguages] objectAtIndex:0]で言語タイプを取得し対応するファイルがあるならそのファイルを対応するファイルがない場合は英語辺りのファイルを表示すればいいだけになります。

正直サーバーあたりに置いてって形式でも良かったのですがアプリの関係上そのやり方が使えずにこんな形に。

訂正
[[NSLocale currentLocale] localeIdentifier]だと書式設定も取得するので比較するのが複雑ですね。

そうCellにUITextView載せるなんて非効率的じゃないのかな?(遠い目

面倒になってUILabelに変えると爆速になった…
高コストなのにeditableもselectableもNOのUITextViewをわざわざCellに載せる必要無いのではないかというプリミティブな疑問にぶち当たりUILabelに変更。
変更なり参照したいなら別枠で開けばOKだと気付いたさ。
ちなみにMessagesもありゃUILabelですな。
attributedText使えばリンクも使えるしって事でこれからは悩まずにUILabel貼っつけておこう。

高さが可変のUITableViewCellでdrawRectを使って角丸のcellを実現

角丸のviewを作りたくdrawRectで描画したもののvisibleのcellはdrawRect呼ばれるのですが、
表示されていないcellが表示される時にdrawRectが呼ばれません。
しっかりと使いまわすと宣言されてるので当たり前といえば当たり前なんですけど一回一回
呼び出す処理をすると何のためにlayerでの描画を回避したのか分からない状況に…
要はheaderとfooterのviewに分けて角丸で実装すべきなんでしょうね。
ということで早速制作


- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        color = [UIColor whiteColor];
    }
    return self;
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    
}

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGFloat r = 10.0;
    CGContextSetFillColorWithColor(c, color.CGColor);
   
    /*header側の描画*/
    CGContextMoveToPoint(c, CGRectGetMinX(rect), CGRectGetMaxY(rect));
    CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMidX(rect), CGRectGetMinY(rect), r);
    CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMidY(rect), r);
    CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
    
    /*footer側の描画*/
    CGContextMoveToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMinY(rect)) ;
    CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect),CGRectGetMidX(rect), CGRectGetMaxY( rect ), r);
    CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMidY(rect), r);
   

    CGContextClosePath(c);
    CGContextFillPath(c);

}

header側のviewとfooter側のviewに分けて描画して下さい。
そして間に可変するviewを挟んだりすると角丸かつ可変でもストレス無く動くcellが完成です!

cellの中で描画する場合値を設定するのにIBInspectableでプロパティを設定しているとStoryboardで簡単に変更できます。

ウェブページ読み込み時間を最大34%短縮するフレームワークという記事を見て

japan.cnet.com

そこまでやるならブラウザに予め幾つかのフレームを用意しておいてフレームIDを指定しそれぞれに渡すデータだけ送信するシステムでよくないか?とふと思った。
データだけでフレームは指定するだけで良いんので面倒な設置の手間が省ける。
入れたいデータのカラムIDと配列データだけで送信とか面白そうですね。

Nibで作ったUITableViewとCellと困ったこと

どちらもAutolayoutで作った場合に少々面倒な事態が発生。
cellを可変高の仕様でcellの中のUITextViewの高さをsizeThatFitsで取得してheightForRowAtIndexPathに反映させようとしても上手く行かない!
で調べた結果tableの横幅とcellの横幅が違う…
cellは計算用に先に取得したものを使って高さをだす予定が全然上手く行かないじゃないですか。
どうやらcellはnibで作った値で取得されておりcellForRowAtIndexPathで合流しその後大きさに合わせてautolayoutすると思われます。
すると計算したい段階でどんなに値が欲しくても取れないじゃないですか…

解決策として横幅を最初から合わせてcellを作るというautolayoutなのか?という状況ですが値が取得されないのでは致し方無い。
ただこの状況で tableView:heightForRowAtIndexPath 内で色々作業をするとカクカクとしたtableが出来上がってしまいます。
そこで tableView:estimatedHeightForRowAtIndexPath 内で処理を施し出た値を配列などで保持して反映させるといいですね。
estimatedHeightForRowAtIndexPathは一旦テーブルの高さを全て算出しその後リロードしないかぎり呼び出されません。
結構適当に値をだしとけって言ってる所多いがheightForRowAtIndexPathでいちいち計算するほうが面倒では?と思ったりするんですがね…

取り敢えず流れです

  1. 横幅の正確なcellを用意するかもしくは代替するUIViewでも用意する。※1
  2. 全体の高さからUITextViewを省いた高さを固定の値を取得。全てtextViewなら不必要です。
  3. estimatedHeightForRowAtIndexPathでtextViewにテキストを入れてsizeThatFitsで高さを取得します。※2
  4. heightForRowAtIndexPathではestimatedHeightForRowAtIndexPathで取得した値を反映させます。

※1 遅延処理してtableの大きさが決まってからtableの大きさを取得してcellのフレームを変更しlayoutIfNeededを実行すれば変更後のcellの中の値を取得出来ます。
※2 取得した値は配列で保持するといいですね。indexPathは必ずrowが0から始まります。なのでrowの値を監視していればreload時の配列の初期化が出来ます。

FMDBでつまずく…

SQLitesql文を作成して実行されて成功しているのに思った通りに反映されない!
でもsqlitebrowserだとしっかりと動くんですよ…

INSERT INTO data( ... ) SELECT ? ,? ,?  WHERE EXISTS ( ... ) AND NOT EXISTS ( ... ); 
UPDATE data SET ... WHERE id = ? AND date < ?;

見ての通りかなり省略されてますが2この実行文が一つのsql文で書かれておりこれを実行すると動くんですが反映されない事態が発生。
ままよとトランザクション中に2このsql文を動かすと成功しました。

    [db open];
    [db beginTransaction];
    for(int i = 0; i < list.count; i++){
        BOOL re = [db executeUpdate:sql1 withArgumentsInArray:@[
                                                               ...
                                                               ]];
        count += re == NO ? 1 : 0;
        BOOL le = [db executeUpdate:sql2 withArgumentsInArray:@[
                                                              ...
                                                               ]];
        
        count += le == NO ? 1 : 0;
    }
    
    if(count == 0){
        [db commit];
        return  YES;
    }else{
        [db rollback];
        return  NO;
    }

こんな適当なのでしっかりと動いてくれるんですね。
じゃ最初に動いてくれよって思うんですがね…
これやっぱり複数の処理を1つに纏めたのが問題なんですかね?
”;”をパースしてくれないのかな?
insertと条件updateを同時にこなそうという無謀がダメでしたか。