窓ぎわのトットちゃん

以前品川区の大崎というところに住んでいたんだが、自宅のとなりに「トット文化館」という障害者のための施設があった。「トット」ってなんだろうと妻に聞いたところ、黒柳徹子さんのあだ名であることがわかった。ふむーと思いつつ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月にまた石川、って感じ。
娘が大きくなったらアメリカにでも行きたいな。

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

iOSアプリでプッシュ通知を完璧にテストする方法

もしかしたらよく知られていることなのかもしれないけど、割とハマったのでメモ。

iOSアプリでプッシュ通知機能のテストは結構面倒である。特に面倒なのが、アプリ初回起動時の挙動のテスト(以下の画像参照)。

iOSのプッシュ機能は以下のような流れで設定される。

  1. アプリ起動時にregisterForRemoteNotificationTypesメソッドを呼ぶ
  2. 端末はアップルのサーバー(APNs)と通信して、プッシュのためのデバイストークンを取得
  3. アプリの初回起動時にのみiOSが「<アプリ名>はあなたにプッシュ通知を送信します。よろしいですか?」というアラートを表示する
  4. 「はい」ボタンを押すと、APNsに端末が登録されプッシュを受信できるようになる

で面倒なのが、初回起動時のみに表示されるアラートのテスト。このアラートは本当に初回起動時にしか表示されず、アプリを一度削除して、再度インストールしても、このアラートは二度と表示されない。

が、以下の手順を踏めば、再度アラートを表示させることができる。

  1. アプリを削除する
  2. Macのシステム時計を2週間ほど早める(!)
  3. iPhoneを再起動する
  4. iPhoneをMacに接続すると、iPhoneのシステム時計が2週間進む
  5. アプリを再インストールする
  6. アラートが表示される

iPhoneの設定で直接時刻すると、Macに接続した瞬間に時間が補正されてしまって元に戻ってしまうので、仕方なくMac側のシステム時計を変更している。

ちなみにiPhoneのシステム時計をあんまり進めすぎるとプロビジョニングプロファイルの有効期限を超えちゃって実機転送できなくなるのでお気をつけて。

詳しくは以下を参照してくださいー。
http://developer.apple.com/library/ios/#technotes/tn2265/_index.html

Resetting the Push Notifications Permissions Alert on iOS
The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.

If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the latter without actually waiting a day by setting the system clock forward a day or more, turning the device off completely, then turning the device back on.

娘のスキル一覧

生まれてから2ヶ月が経過し、横顔が父親に似てきた娘だが、ここで一旦彼女がこれまでに習得したスキルを整理してみる。

  • 生後1ヶ月までに習得したスキル
    • 寝る
    • 起きる
    • おしっことうんちをする
    • 乳を吸う
    • ときどき吐く
    • 泣く
    • へっへっ、あ〜、う〜、う”〜、などと発声する
    • 何かを見つめる
  • 生後2ヶ月までに習得したスキル
    • 拳をしゃぶる [New!]

あと6年くらいしたら「FizzBuzz問題を解ける」くらいに成長してるといいな!

iPadのGarageBand+iRigで簡単多重録音

iRigを買ったらiPadGarageBandがかなり実用的な多重録音環境となった。おもろい!

以下がiPadで録音した音楽。
Download
http://kenmaz.net/tmp/bambina.mp3

こんな感じで録音/編集する。

ちなみにiRigってのは、ギターとiPadをつなげるようなやつ。

IK Multimedia iRig IPIRIGPLGIN

IK Multimedia iRig IPIRIGPLGIN