iOSアプリ開発でCI環境整えるための簡易メモ

 

前提

ghunitとかでテスト書いておく

jenkinsサーバを適当に立てる

 

make testでビルド&ghunitテスト実行できるようにする

http://gabriel.github.com/gh-unit/docs/appledoc_include/guide_command_line.html

 

macにslave.jar落としてきててエージェント起動

http://textt.net/take_cheeze/20110626042525/57

 

スレーブにmacを登録

http://unicus.jp/skmk/archives/153

 

カバレッジをとる

http://www.tokoro.me/2012/09/02/ghunit-jenkins-coverage/

 

Clang scan-build bug trend

TODO

 

こんだけあれば十分かな?

 

git mergeのbug?

XCodeのプロジェクトをgitで管理している際に、mergeでいろいろと問題が起きたのでメモっておく。

XCodeのプロジェクトを作ると、プロジェクトのファイル・グループ構造を管理するxxx.pbxprojというファイルがXCodeによって自動生成される。内容はjsonっぽい形式(property list)のテキストファイルだが、XCodeがプロジェクトの構成を管理するために簡易データベース的に使っているファイルなので、基本的には人間がいじっちゃいけないファイルである。

プロジェクトにファイルを追加するとpbxprojの内容が書き換わるので、gitなどでチーム開発するとどうしても頻繁に更新が入り、pbxprojがコンフリクトしてしまう。コンフリクトするたびに、本来人間が編集すべきでないpbxprojをテキストエディタで開き、<<<とか>>>でgrepして手作業で修正、とかチマチマやる必要がある。だるい。

ということで、このへんのダルさを解決するための方法が以下のページで紹介されていた。

http://robots.thoughtbot.com/post/33796217972/xcode-and-git-bridging-the-gap

.gitattributesというファイルにpbxprojはバイナリファイルであることを指定することで、テキストデータではなくバイナリファイルとしてマージさせる、というもの。こうすることでコンフリクトが発生したときにgitがupstreamのファイルを優先で自動でマージしてくれる、という話。

確かにこの方法であれば、コンフリクトせず良い感じにマージしている「ように見える」のだが、たまに構造的に誤ったマージをしてしまうことがある。しかし、git mergeコマンド自体は成功してしたことになっているの、上手く言ったように見えて実はpbxprojがぶっ壊れてる、という状態になってしまうことがある。

 

例えば、こんな感じのXCodeのpbxproj形式のファイルがmasterにあったとする

f:id:kenmaz:20130131222816p:plain

ここでfooというブランチを切って、このpbxprojを以下のように修正してコミットする。

f:id:kenmaz:20130131222823p:plain

一方で、masterブランチのほうにも以下のような修正を加えてコミットする(fooブランチと似たような場所・内容の修正)。

f:id:kenmaz:20130131222820p:plain

で、.gitattributesの設定をした上で、fooの修正をmasterにマージする。 すると以下のように意図しない、誤ったマージをしてしまう(git mergeコマンドは成功したことになっている)。

f:id:kenmaz:20130131222826p:plain

ちなみに、.gitattributeを設定しなければ、以下のようにコンフリクトが発生する。ということでテキストエディタでマージ解消するんだが、よくみるとこちらの差分もやっぱりちょっとおかしい感じになってしまっている。

f:id:kenmaz:20130131222833p:plain

 

結論

.gitattributeを設定して楽しようとするとすると思わぬマージ結果になっちゃうことがあるので、ちゃんとコミット前に目視で確認するか、そもそも.gitattribute指定しないほうがいい。

なんか他に良い解決方法があれば教えて下さい。

 

 

人生初のコミックマーケット(C83)に参加

会社の同僚が何人か出展するとのことで、生まれて初めてコミケに一人で行ってみることにしました。 

会場の様子

こちらが会場となる国際展示場。到着したのは14:30くらい。ぎゅうぎゅう、というわけではないけど、やっぱりかなり人が多かったです。

f:id:kenmaz:20121229143719j:plain

どこへいったらいいかも分からないでの、とりあえず同僚のCさんが売り子をしている場所まで向かうことに。Cさんのツイッターをみると「@土曜東W12a」(記号は適当)みたいなことを書いてあったので、それを頼りに探す。

会場は「東」「西」の二つのエリアに分かれている様子。目的地は東っぽいのでそちらに向かう。西にはいったい何があったんだろう。

東エリアに到着。

f:id:kenmaz:20121229144516j:plain

エスカレーターを下ると広いホールを発見。壁に大きく「A」とか「Z」とか「あ」とか巨大な張り紙がしてある。これを頼りに目的地を探せばいいわけね。

f:id:kenmaz:20121229144605j:plain

最初に入ったホールとは別にもう一つ大きいホールがあって、そちらに目的地を発見。全部で2ホールなのかな?

各売り場は「サークル」単位で長机が割り当てられていて、そこに例の「薄い本」が並べられていた。サークルっていうくらいだから何人かでわいわいやっているのかなーと思ったけどCさんは一人でぽつねんとパイプイスに座っておられた。ちなみに他の同僚はみんな3日目の出展のようだ。残念。

残念ながらCさん作の薄い本は僕の趣向には合わなかったため購入は見送らせていただいた。少し雑談したあと、会場内を散策へ。

ホール内には長机がこれでもかというほど並べられており、全てのサークルを回ることは無理そうな感じだった。通常は事前にカタログを購入してお目当てのサークルを探してから計画的に回るものらしいが、今回はひたすら歩いてみて回ることにした。 

感想

コミケというと「二次創作のオタクっぽい同人マンガが売り買いされている場所」というイメージがあった。実際に小一時間会場を見て回った印象はこんな感じ。

  • 美少女二次創作マンガ、的な本がやはり多い
  • 大体会場の1/3くらいは、売り手も書い手も女子。本の内容はまあ腐女子系というのだろうか、ボーイズラブ的な、少女漫画的な、そんな感じ
  • もう1/3は、オタク男子のための萌え系っぽい、いかにもって感じの本。売り手買い手もそんな感じ
  • のこり1/3は、マンガや萌えではなく、たとえば旅行記、写真集、評論、模型、とか、わりと一般趣味書籍っぽい感じ
  • ゲームとか、ワンピースのようなメジャーコンテンツの二次創作はあまり見られなかった。もしかして3日間でジャンル分けがされているんだろうか。
  • 過激なエロとか暴力とかそういうのもあんまりなく、いたって平和的なコンテンツが多かったような印象

また会場自体に関しては以下の点が気になった。

  • 各サークルは列ごとにジャンル分けされている。島ではなく列ごとに分けられているっぽい。このおかげで、左右をきょろきょろしながら真ん中の通路をあるけば、大体この列はこんなジャンルの列なのね、ってことが探しやすくなっている。
  • ボランティア?っぽい人たちが大量にいて、会場の見回りをしたり、本部っぽいところで案内をしたりしている。ボランティなのかな?お金貰っているのかな?
  • コスプレイヤーはどこに!?
  • 16:00に終了。会場内全員で謎の三本締め。ほんわかした。

戦利品

そういうわけで、誰の案内もなく、一人でコミケに潜入して、よく分からないところも多々ありつつも、2時間くらい滞在した。買ったものは以下。

f:id:kenmaz:20121230020116j:plain

大阪と東京の高層ビルの写真とひとことが書かれた本。装丁がかなりしっかりしている。僕も結構高層ビルはすきなので楽しめた。東京の「環状2号線プロジェクト」と「大阪東京海上日動ビル」が気になったのでいつか確認しにいこう。あと、やっぱり六本木ヒルズの森タワーは好きだ。

発行:超高層ビルを愛でる会。¥400くらい。

f:id:kenmaz:20121230020202j:plain

ミニ四駆の(再)入門書。かなりボリュームのある一冊。小学校の遠足のしおりのような、手作り感あふれる装丁。最近のミニ四駆シャーシの動向から、作り方・チューンナップのコツ、そして公式大会に出場するまでの流れまでがぎっしり書かれている。小学校3,4年くらいのときに2度ほど公式大会にでたことがあるけど、公式大会ならではの巨大なコースはわくわくしますね。機会と気力があればミニ四駆、久しぶりに触ってみたい。

発行:犬神研究所。¥400くらい

f:id:kenmaz:20121230020148j:plain

工場から、官公庁、酒造、東京証券取引所、皇居、など関東のさまざまなスポットに関するレポートがまとめられたもの。いかにも面白そうな内容だったので1,2巻まとめて買った。さらにコカコーラ工場見学の経験をもとに書かれた「MMRコカコーラの陰謀」というマンガも購入。

発行:とこしえ工房。¥200〜¥300くらい。

 

以上、3サークルで買い物しました。まずどれも非常に安くて、¥200〜¥700くらいで、ちょっと普通の本屋にはおいてないようなマニアックな本が買えて、なかなか楽しかったです。2,3日目は行かないんだけど、プログラミング技術系の本とか、古いTVゲームに関するエッセイとか、あとはロックとか音楽系の本とか、そういうものがあれば欲しいかなーと思いました。今度は夏?かな。また行こうかな。

さいごに

ついでにと言ってはなんですが、2012年もいろいろお世話になりました。2012年統括的なブログを別途書くかどうかは未定。

2013年は、とりあえずアレをアレしなきゃなー。関係各所のみなさま、いろいろとお世話になりそうですが、どうかよろしくお願いします。

窓ぎわのトットちゃん

以前品川区の大崎というところに住んでいたんだが、自宅のとなりに「トット文化館」という障害者のための施設があった。「トット」ってなんだろうと妻に聞いたところ、黒柳徹子さんのあだ名であることがわかった。ふむーと思いつつ4年くらい大崎に住んで、いまは別のところに住んでます。

それでたまたま誰かのブログで「窓ぎわのトットちゃん」という本の話がでてて、そういえばまだ読んでないなーと思い、妻にたのんで図書館で借りてきてもらって読みました。

話の舞台となるトモエ学園、校長先生、そしてトットちゃん含め生徒全員がとても自然で優しくていい感じでした。

うちの娘もぜひこんな感じに育ってくれるといいな〜と。

窓ぎわのトットちゃん (講談社文庫)

窓ぎわのトットちゃん (講談社文庫)

 

 

解いてみた/ザッカーバーグの面接試験2:アクティビティ・インディケーター

ザッカーバーグの面接試験2:アクティビティ・インディケーター
http://satoshi.blogs.com/life/2012/08/zack2.html

こんな感じかな?

#import "NetworkActivityManager.h"

@implementation NetworkActivityManager

+ (id) sharedInstance {
    static NetworkActivityManager* manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[NetworkActivityManager alloc] init];
    });
    return manager;
}

- (id)retain {
    [super retain];
    if ([self retainCount] > 1) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    }
    return self;
}

- (oneway void)release {
    [super release];
    if ([self retainCount] <= 1) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    }
}

また、このケースで、シングルトンへのstrong referenceを使う利点と欠点を述べてください。

・利点:Reference countがインジケータのON/OFFスイッチの代わりにつかえてシンプルに書ける
・欠点:うーん、とくに思いつかない。関係ないところでは、上のコードはARC対象外になっちゃうので微妙ってくらいかなぁ。。

GCDとpthraedのコード比較

Grand Central Dispathでで並列プログラミングする場合に、条件変数(Condition Variable)を使いたい時はどうすればいいのかみたいな話を同僚としてたので調べてみた。結論としてはpthread_cond_xxxを使えばOK。

ところで私はpthreadもGCDもそんなに詳しくないので、学習がてら小さいコードを書いて両者を比較してみることにした。

pthreadで並列プログラミング

まずはGCDを使わずに、pthreadを使ってマルチスレッドなコードを実装。適当にpthreadでぐぐったら、codezine良い感じの記事とサンプルコードがあったので、これをベースにする(一部いじってある)

引用元:CodeZine「pthreadについて(条件変数・モデル)」
http://codezine.jp/article/detail/1894

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define THREAD_MAX 256

void* tmp_func(void* arg);

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;

int start_flg = 0; //(2)pthread_cond_broadcast受け取り漏れ対策

int main(int argc, char** argv) {
    pthread_t pt[THREAD_MAX];
    int thr_count = 10;
    
    pthread_mutex_lock(&ready_mutex);
    for (int i = 0; i < thr_count; i++) {
        pthread_create(&pt[i], 0, tmp_func, &i);  //(1)indexの受け渡し対策
        pthread_cond_wait(&ready_cond, &ready_mutex);
    }
    pthread_mutex_unlock(&ready_mutex);
    
    sleep(1);
    
    start_flg = 1;
    fprintf(stdout, "pthread_cond_broadcast\n");
    pthread_cond_broadcast(&cond);
    for (i = 0; i < thr_count; i++) {
        pthread_join(pt[i], 0);
    }
    return 0;
}

void* tmp_func(void* arg) {
    pthread_mutex_lock(&ready_mutex); //(3)signal発行前に呼び出し元でwaitしていることを担保
    int index = *(int*)arg;
    pthread_cond_signal(&ready_cond);
    pthread_mutex_unlock(&ready_mutex);
    
    fprintf(stdout, "start thread index:[%d]\n", index);
    pthread_mutex_lock(&mutex);
    
    while (start_flg == 0) {
        pthread_cond_wait(&cond, &mutex);
    }

    pthread_mutex_unlock(&mutex);
    fprintf(stdout, "end thread index:[%d]\n", index);
    return 0;
}

このコードは以下の様なことをやっている。

  • 10個のスレッドを起動する
  • 各スレッドには起動時にindexが与えられる
  • 各スレッドは条件変数により待機状態になる
  • 全てのスレッドが起動しきったところで、待機しているスレッドを起こす
  • 全てのスレッドの実行が完了したらプログラム終了

これだけだが、そのままだといくつか問題があるので以下のように対処している。

  • (1)でスレッド側でiのポインタを渡す際に、呼び出し元でiの値を書き変えてしまわないように、条件変数ready_condを使ってガード
  • 最後に生成されるスレッドがwaitする前に、pthread_cond_broadcastされると、broadcastを受け取ることなくwaitしつづけるので、(2)のstart_flg変数でwaitするしないを制御
  • スレッド側で変数iを受けとってpthread_cond_signalを発行する際に、呼び出し元でwaitしていることを担保するために(3)でready_mutexをロック

ややこしいですねぇ。

GCDで並列プログラミング

上記プログラムを、GCDを使って書き換えた結果がこちら。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <dispatch/dispatch.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  cond = PTHREAD_COND_INITIALIZER;

int start_flg = 0; //(c)

int main( int argc, char ** argv ) {
    int thr_count = 10;
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    for (int i = 0; i < thr_count; i ++ ) {
        dispatch_group_async(group, queue, ^{
            int  index = i; //(b)
            fprintf( stdout, "start thread index:[%d] input!!\n", index );
            pthread_mutex_lock( &mutex );
            while (start_flg == 0) {
                pthread_cond_wait( &cond, &mutex );  //(d)
            }
            pthread_mutex_unlock( &mutex ) ;
            fprintf( stdout, "end thread index:[%d] output!!\n", index );
        });
    }
    sleep( 1 );

    start_flg = 1;
    pthread_cond_broadcast( &cond );
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER); //(a)
    dispatch_release(group);
    return 0;
}

なんかだいぶスッキリした気がします。

ポイントは以下。

  • まずはblocksで無名関数がかけるのでスッキリ
  • joinのかわりにdispath_group_waitを使って、待ち合わせ処理がスッキリ (a)
  • 変数iの値は(b)の時点でblocksによってキャプチャされるので、iの受け渡しのために条件変数と同期変数を使う必要がなくなってスッキリ
  • start_flgが必要なのはかわらず(c)
  • GCDを使っていてもpthread_condやmutexは問題なく使用可能(d)

GCDとblocksによってかなりスッキリして良い感じです。GCDによってスレッドの制御も最適化されて性能的にも良さげです。

このへんの話は以下の資料、書籍も参考になります。

並列プログラミングガイド
https://developer.apple.com/jp/devcenter/ios/library/documentation/ConcurrencyProgrammingGuide.pdf

エキスパートObjective-Cプログラミング ― iOS/OS Xのメモリ管理とマルチスレッド
http://tatsu-zine.com/books/objc

怪しい点があればご指摘ください。

2012/07/01 21:01追記

  • start_flgやめてdispatch_semaphoreをカウントダウンラッチ的に使えばいいね

2011まとめ

仕事

1月

1月から新プロジェクトが立ち上がり、10月ごろまで掛け持ちで開発リーダーをやった。

3月

震災発生。地震発生時はエイプリルフール企画のMTGをやっていた真っ最中だった。ビルもすごい揺れた。地震発生直後からiPhoneでもNHKとかのサイマル放送をやることになったので、開発チーム総出で24H監視を行った。ちょっとは人様のお役に立てただろうか。

4月

スマホ関係の有料セミナーの講師をやった。

6月

元々やっていたほうプロジェクトの責任者になった。んで会長の別荘に行って作戦会議を行った。軽井沢の別荘は異世界だった。

8月

もう一方のプロジェクトで火事を起してしまった。8月はしんどかったな・・。反省。そして開発リーダーの掛け持ちは無理ってことがわかったので、そっちは別の方にお願いした。

10月

組織体制が変わって開発以外のこともよく見るようになった。売上とか売上とか。とはいえ11月〜12月は結構コード書いたな

全体

2010年以前にくらべて(色々ヘマもやらかしたが)より真面目に責任感を持って仕事に取り組めたような気がする。今の職場でも学ぶことはまだまだある気がする。

プライベートとか趣味とか

なんといっても5月に娘が生まれた。すごくかわいい。ありがとう妻〜ッ。
初めて病院から連れて帰ってきたときは、なんて小さくて儚い存在なんだ!と思ったが、7ヶ月目の今となっては存在感ありまくりで、元気に毎日、泣いたり、笑ったり、ウンチしたりしてます。
そういえば2011年の大晦日にはじめて喋った。何を喋っているかは不明だが「てんてん・・」みたいなことをつぶやいている。。

寄稿

仕事や子育てが忙しくなってきたので、2年半くらい続けてきた日経ソフトウエアへの寄稿を一旦終わらせてもらった。
かなり大変だったけど、よい経験となった。

Apple

iMacとMacBookAirとiPad2と、2011年もアップル製品をいろいろ買った
ジョブズが生きている間にWWDC行きたかった・・。合掌。

趣味の開発

どっちかと言えば、休日でも時間があまったら仕事のコードを書いてた。
ってことで2011年は、まとまった成果物はそれほどないな。
会社のハッカソンで作ったもの:http://www.kenmaz.net/html5/animemaker/

新しくはじめたこと

冬休みから、ふとした思いつきで電子工作を始めた。いつまで続くかな。
ドラムもよく練習していたけど、最近はやってないなー。

旅行

1月に石川県の実家&温泉、2月に箱根、9月にまた石川、って感じ。
娘が大きくなったらアメリカにでも行きたいな。

なわけで、今年もよろしく。