2012年12月16日日曜日

NSDictionaryの特定のキーでソートしちゃる

どうも、俺@まだ勉強中です。

例えばNSArray(またはNSMutableArray)内にNSDictionaryが複数入っているとして、そのNSArrayをNSDictionaryのとあるキーでソートしたい場合。

NSArray *array = [NSArray arrayWithObjects:@[
        @{@"id":@100, @"name":@"bob"},
        @{@"id":@14,  @"name":@"ken"},
        @{@"id":@531, @"name":@"john"},
        @{@"id":@32,  @"name":@"mike"},
        @{@"id":@65,  @"name":@"kozy"},
        @{@"id":@174, @"name":@"shorn"},
        @{@"id":@7,   @"name":@"scott"},
        @{@"id":@865, @"name":@"mikeal"},
        @{@"id":@31,  @"name":@"fun"}
    ]];
このarrayを格納しているNSDictionaryのキー:idでソートしちゃりたい!場合は、
// NSSortDescriptorを生成して
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES];
// 配列に入れておいて
NSArray *sortarray = [NSArray arrayWithObject:sortDescriptor];
// ソートしちゃる!
NSArray *resultarray = [array sortedArrayUsingDescriptors:sortarray];
// 不要なオブジェクトは解放しちゃる
[sortDescriptor release];
これでキー:idの値でソートされます。


以上でぇぇえぇぇぇえぇす。

Objective-Cの高速列挙は順番保証されない

どうも、俺@勉強中です。

Objective-Cの高速列挙(for ... in ...)は配列全体を走査するのにとても便利なんだけど、取得される順番が保証されません。
# NSDictonaryのキーの順番通りに値を取り出したい!とする。
NSDictionary *dictionary = @{
    @"1": @{@"name":@"bob"},
    @"2": @{@"name":@"ken"},
    @"3": @{@"name":@"john"},
    @"4": @{@"name":@"mike"},
    @"5": @{@"name":@"kozy"},
    @"6": @{@"name":@"shorn"},
    @"7": @{@"name":@"scott"},
    @"8": @{@"name":@"mikeal"},
    @"9": @{@"name":@"fun"}
};

for (id key in dictionary) {
    NSLog(@"%@", key); // 1,2,3,...と出てくれない
}
順番通りに取り出したい時困る。
なので回避策としてNSArray#sortedArrayUsingComparatorを使う方法があります。
// 一旦NSDictionaryのキーを取得して
NSArray *keys = [dictionary allKeys];

// sortedArrayUsingComparatorを使ってキーをソート
keys = [keys sortedArrayUsingComparator:^(id o1, id o2) {
    return [o1 compare:o2];
}];

// 確認すると順番通りそ
NSLog(@"%@", keys);
NSMutableArray *array = [NSMutableArray array];

// あとは順番通りに値を取得する
for (id key in keys) {
    [array addObject:[dictionary objectForKey:key]];
}

// 完璧!
NSLog(@"%@", array);
これで最初のNSDictionaryのキー順番通りに値を取得できます

以上でぇぇえぇぇす。

2012年12月14日金曜日

NSStringのstringWithFormatで小数点以下をええ感じにする

どうも、俺@昼休みです。
 ここ数日はブログへのPOSTが多いですね。開発してると小ネタをよく見つけます。

今日はObjective-CのNSString#stringWithFormatメソッドについてです。
 例えば、100を文字列で表す場合は
[NSString stringWithFormat:@"%d", 100];
ですね。 0.1を表す場合は
[NSString stringWithFormat:@"%.1f", 0.1f];
です。 0.12345の場合は
[NSString stringWithFormat:@"%.5f", 0.12345f];
です。 小数点以下の桁数が決まっている場合は良いのですが、上の0.12345のフォーマットで0.1を表したい場合は、
[NSString stringWithFormat:@"%.5f", 0.1f];
// 結果は0.10000
となってしまいます。 出来れば0.1と表示させたい!という場合に便利なフォーマットは、
[NSString stringWithFormat:@"%g", 0.1f];
// 結果は0.1
[NSString stringWithFormat:@"%g", 0.12345f];
// 結果は0.12345
になります。

 以上でぇぇぇえぇす。

2012年12月13日木曜日

Retinaディスプレイかどうかの判別

どうも、俺@コーディング中です。
ギークな感じでいいでしょう。

Objective-CでRetinaディスプレイかどうかを判別する方法をφ(..)メモメモ。

[UIScreen mainScreen].scale
の値が
1.0なら非Retina
2.0ならRetina
です。

ちなみにOSのバージョンの取得方法は、
[UIDevice currentDevice] systemVersion]
で、
例えば「iOS5.0以上」というような条件分岐をする場合、
float version = [[[UIDevice currentDevice] systemVersion] floatValue];

if (version >= 5.0f) {
  // 5.0以上の処理
}
というように書けます!

以上でぇぇぇぇぇす。

2012年12月12日水曜日

1つの.vimrcにユーザ毎の設定をする

どうも、俺@仕事中です。
今日は.vimrcにログインユーザ別の設定を書く方法をめもめも。
 
あまりないパターンかもしれませんが、 例えばLinux本番サーバの運用方法などで、
 「ログインユーザは各開発者毎に用意されているがソースや設定ファイルの変更は共通のユーザになってからでないと編集したらダメ!」
というようなルールが設定されているような場合、
$ su someuser
とかで共通ユーザになってから作業するのですが、
この時の.vimrcがこの事務所内の誰かが設定した.vimrcだった場合に
「何やこの設定!?」となってしまう事もありえると思います。 
そういう場合は.vimrcにログインユーザ毎の設定を書いちゃえば万事OKです!
if $USER == 'koexuka'
  set enc=utf8
  set fenc=utf8
  set hlsearch
  .
  .
  .
endif
など。
 もちろん $USER を他の環境変数に書き換えて使うこともできちゃいます!

 以上でぇぇぇえぇぇぇす。

2012年11月28日水曜日

Androidアプリ開発でのメモリ使用量確認

どうも、俺@残業中で腹減ったです。
最近はAndroidアプリ開発にも手を出しています。eclipse超高機能で便利ですね。

さて、Androidアプリを開発してるとOutOfMemoryに悩まされる開発者の方々多いのではないでしょうか。
僕も悩みまくっていまして、ググると大量に関連した記事が出てきます。
Xcodeだとinstrumentsというツールでメモリリークを調べたりできますが、もちろんeclipseでも可能です。
という訳で、それらをまとめてアプリのメモリ使用量について確認したいと思います。

※環境
Mac OSX 10.8.2
eclipse JUNO SR 1

その1)DDMS
実機転送またはエミュレータでアプリ起動中に、eclipseのDDMSでメモリ量を確認できます。
まずDDMS画面に切り替えます。

次に左側のペインから対象のアプリパッケージを選択します。
※開発中のものがあるので画像加工しています。。

そして、その上部にある「Update Heap」をクリック。

そして、その右側にあるペインから「Heap」タブを選択し「Cause GC」をクリックします。
これはGCが走らないとHeap状況が出ないからなので、GCが走るのを待っても良いです。

そうするとGCが走る度にメモリ使用量が更新されていきます。

HeapSizeは確保されているメモリ量で必要に応じてメモリが確保され増えていきます。
増え続けると限界値まで増えます。
限界値は
Runtime.getRuntime().maxMemory()
で確認可能。
限界値はエミュレータの場合は、Android Virtual Device Managerで設定するMax VM application heap sizeです。


Allocatedは使用中のメモリ量です。
このDDMSでどのくらいHeapが確保されていて、どのくらい使われているのかを確認します。
ちなみにここで言うHeapはDalvikヒープのことを指しているようです。

Androidアプリ自身には、
・ネイティブヒープ
・Dalvikヒープ
の2種類のヒープがあるようです。
あと端末自体に割り当てられているLinuxヒープというのもありますが。

■ネイティブヒープ
Andorid3.0以前であれば、主にBitmapデータを確保するために利用されます。
// 全体ネイティブサイズ
Debug.getNativeHeapSize();

// 使用中ネイティブヒープサイズ
Debug.getNativeHeapAllocatedSize();

// 空きネイティブヒープサイズ
Debug.getNativeHeapFreeSize();
で確認できます。
■Dalvikヒープ
クラスのインスタンスやBitmap(Android3.0以降)データを確保するために使われます。
// 確保されたDalvikヒープサイズ
Runtime.getRuntime().totalMemory();

// メモリが足りない場合に確保しようとする最大のDalvikヒープサイズ
Runtime.getRuntime().maxMemory();

// 空きDalvikヒープサイズ
Runtime.getRuntime().freeMemory();

// 使用中Dalvikヒープサイズ
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
で確認できます。
このネイティブヒープとDalvikヒープの使用合計サイズが最大値を超えるとOutOfMemoryが発生してしまうのです。
Androidのバージョンが低い端末だと、割り当てられるメモリ量が少ないために、画像生成時などにメモリ枯渇によりアプリが落ちてしまう事が多々あるようです。
特にBitmap系でのOutOfMemoryの場合は、画像サイズをいかに小さくするかで割りと解決出来たりします。


以上でぇぇえぇす。

2012年11月23日金曜日

Androidアプリで "R cannot be resolved to a variable"エラー

どうも、俺@3連休です。
最近はAndroidアプリの開発にも手を出しております。

サーバサイドはvimでコーディング、iOSアプリはxcodeで開発してたのですが最近はもっぱらeclipseです。
eclipseの豊富な機能に圧倒されております。

さてタイトルの件ですが、Androidアプリ開発をしてるとたまに目にするエラーのようで、ググルと多くのサイトに解決方法が書いてますね。
原因はプロジェクト内のgenディレクトリ内に生成されるR.javaが消えてなくなってたり、更新されなくなってたり、ということのようです。
R.javaはリソースに関するデータを扱う自動生成されるプログラムファイルです。

なぜ消えてなくなったり、更新されなくなるのか?の部分を直してやれば解決します。
そのいくつかをご紹介します。

■解決方法
・CleanしてBuildしてやる。
・eclipseを再起動。
・eclipseを終了して、プロジェクト内のgenディレクトリをまるごと削除しeclipse起動。
・resディレクトリ以下にあるxmlファイルに記述ミスがあるので直してやる。
 →consoleにエラーログが出力されているはずなのでチェック。
・なぜか別の android.R; がインポート宣言されちゃっている。それじゃないです。
 →あったら削除。

ちなみに僕も同様の現象が発生し、そのどれを試しても直りませんでした。
ですがMacごと再起動しeclipseを立ち上げたらなぜか直りました。
超レアケースかも知れませんが、最終的には開発端末ごと再起動でなんとかなるかも知れませんよ!


以上でぇぇえぇぇす。


2012年11月10日土曜日

iPhoneゲームアプリ「石積み族」リリースしました!

どうも、俺@休日です。
 11/8にiPhoneアプリ「石積み族」をリリースすることが出来ました。
  石積み族(app storeへ)


 cocos2d v1.0.1での開発です。
 開発着手からリリースまでかなり長い時間をかけてしまったので、以降はもっと短期間で開発できるようにしなければいけません(汗
 iPhoneをお持ちの方は一度遊んでみて下さい!

 以上でぇぇぇぇえす。

2012年10月5日金曜日

findコマンドで複数ファイル名パターンから検索する

どうも、俺@始業前です。

findコマンドで、例えばファイル名が「*.php」と「*.html」にマッチするファイルを検索したい場合。
$ find ./ ¥( -name *.php -o -name *.html ¥)
です。

以上でぇぇぇぇぇす。

2012年10月3日水曜日

Xenの仮想サーバ(ゲストOS)で時刻設定ができない

どうも、俺@仕事中です。
決してさぼってブログを書いている訳ではありません。

タイトル通りですが、xenのゲストOSで
# date 100316:50
とか
# /usr/sbin/ntpdate xxx.xxx.xxx.xxx
とかやっても時刻が合わない場合。
このブログエントリーに辿り着いた人は、恐らくあの手この手を尽くした結果このエントリーに辿り着いた事でしょう。

XenのDomUでNTPを使う|検閲TECH
にあるように、XenhaDom0からのみ時刻を設定できるというXenの仕様のせいです。

この場合はゲストOS側で
# vim /etc/sysctl.conf
-------------------------
# 以下を追加
xen.independent_wallclock = 1
して
# sysctl -p
しましょう。

以上でぇぇぇえっぇす。

2012年9月13日木曜日

Facebook sdk(php)でログアウト実装

どうも、俺@残業中です。
またブログさぼっておりました。仕事していないわけではありません^^;
最近はもっぱらObjective-Cの世界にどっぷりです。


さて、今日はfacebookで提供されているphp版のAPIでログアウトする方法についてメモ。

サンプルはこちら。
$facebook = new Facebook(array('appId'=>'xxxxxx', 'secret'=>'zzzzzzzz'));

// ログアウトする
$url = $facebook->getLogoutUrl();
$facebook->destroySession();
header('location:'. $url);


以上でぇぇえぇす。

2012年8月7日火曜日

UIViewをcocos2dに配置する

どうも、俺@残業中です。
久々のエントリー。仕事サボってた訳ではございません^^;バタバタしてました!


今日はUIViewをcocos2dで利用する場合のメモメモです。

UIView *myView = [UIView alloc] init];
[[[CCDirector sharedDirector] openGLView] addSubView:myView];
簡単ですね。

cocos2dでゲームアプリを開発しながら、UIViewなオブジェクトを貼り付けたいとき!はこの方法でOK!


以上でぇぇぇえぇす!


2012年7月4日水曜日

Node.jsで手動GCをかける

どうも、オレ@残業中です。

今日はNodeアプリケーションで任意のタイミングでGCをかける方法をめもめも。
nodejs_jpグループ内で、メモリリークに質問してたら@shigekiさんに教わりました。
※その時の質問はコチラ(https://groups.google.com/forum/#!topic/nodejs_jp/WcbaEZndexE)
※@shigekiさんのサンプルソースはコチラ(https://gist.github.com/2840165)

Nodeを起動するときに

$ node --nouse_idle_notification and --expose_gc app.jp
のようにして起動させます。


GCをかける時は、プログラム内に

global.gc();
を追加します。


参考サイトはこちら
MANUALLY RUN GC IN NODE.JS - DEV JAR
V8エンジンのGCはこれからも改良されていき、またV8がNodeに反映されるまでも少しタイムラグがあるみたいですが、
これから少しずつ改良されていくことに期待です。


以上でぇえぇぇぇす。

2012年7月3日火曜日

Node.jsをv0.8.1にしたらexpressがv3.0.0 beta4になって動かなくなった

どうも、オレ@お昼休みです。
Nodeが一気にv0.6.19からv0.8.1になったという知らせを受けて早速バージョンアップしました。

$ nave install stable

何かが動かなくなるだろうな、と思いながらテスト用に作ってあるexpress+socket.io製app.jsを起動しようとすると案の定動きませんでした。
「動きません」というか起動はするのですが、socket.ioを使ったwebsocket接続ができませんでした。
接続してもうんともすんとも言わない状況です。

expressのhello-worldサンプルのがるGitを見ると、どうもexpressの使い方が以前と変わってるみたい。
→createServer()が必要なくなったぽい。

なので、サンプルに習ってこう書き換えます。(部分抜粋)

$ vim app.js

---------------------------------
var express = require('express');
// これはもう使わない
// var app = module.exports = express.createServer();
var app = express();

var io = require('socket.io');

// 使わない
// app.listen(3000, function() {
//    console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
//});

var socket = io.listen(app.listen(3000));
これでバッチリ



以上でぇぇえぇぇす。

2012年6月7日木曜日

mroongaをインストール

どうも、俺@残業中です。
今日はMySQLの全文検索エンジンmroonga(v2.03)をインストールする方法をメモメモ。
超簡単です。
公式サイトはこちら

MySQL(v5.5.25)はインストール済みとします。(今度こっちのインストール方法もメモメモしとかな)

まずはgroongaインストール。(yumインストール)
# rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-0.noarch.rpm
# yum install groonga-devel

ちなみにgroongaをソースからインストールする場合は
# yum install mecab-devel
しておいて

# wget http://packages.groonga.org/source/groonga/groonga-2.0.3.tar.gz
# tar zxvf groonga-2.0.3.tar.gz
# cd groonga-2.0.3
# ./configure
# make -j$(grep '^processor' /proc/cpuinfo | wc -l)
# mak install
とします。
※未検証です。ここを参考にしてみてください。



次に辞書をインストール。(MeCabの辞書)ソースインストールした場合はmecab-develの中に入ってるかも?

# yum install mecab-ipadic

ここまででとりあえずgroongaはインストールされました。
/usr/lib以下にgroongaというディレクトリが出来てると思います。




いよいよmroongaインストール。

# wget 'https://github.com/downloads/mroonga/mroonga/mroonga-2.03.ta.gz'
# tar zxvf mroonga-2.03.ta.gz
# cd mroonga-2.03



configureしてmakeしてmake installします。

# ./configure --with-mysql-source=/path/to/mysql --with-mysql-config=/path/to/mysql/bin/mysql_config --with-default-parser=TokenMecab
# make
# make install
これでMySQLのプラグインディレクトリ以下にha_mroonga.soが生成されます。
例)/usr/local/mysql-5.5.25/lib/plugin/ha_groonga.so



mysqldを起動または再起動してmysqlにログインします。

# /path/to/mysql/bin/mysql
mysql> INSTALL PLUGIN mroonga SONAME 'ha_mroonga.so';
mysql> SHOW ENGINES;

+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                    | Transactions | XA   | Savepoints |
+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
| CSV                | YES     | CSV storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                      | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                         | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                      | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables  | NO           | NO   | NO         |
| mroonga            | YES     | CJK-ready fulltext search, column store                    | NO           | NO   | NO         |
+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
7 rows in set (0.02 sec)
Yes!インストールでけた!


あとはCREATE TABLEする時に

 ENGINE=mroonga;
をつけてね!






以上でぇぇぇえぇす。

2012年6月3日日曜日

log4jsを使う

どうも、俺@自主勉中です。

今日はjavasscript(今回はNode.js利用)でシステム構築するときにとても便利なlog4jsの紹介です。

インストールはnpmで

$ npm -g install log4js

使い方は
var log4js = require(‘log4js’);
// 設定
log4js.configure({
  appenders: [
    { type: ‘console’, category: ‘console’ },
    { type: ‘file’, filename: ‘logs/access_log’, category: ‘access_log’, backups: 30, maxLogSize: 1024 * 1024 }
  ]
});

var consoleLog = log4js.getLogger(‘console’)
  ,accessLog = log4js.getLogger(‘access_log’);
consoleLog.info(’Server Start.');
accessLog.info(‘This is test(access_log)’);
こんな感じです。
configure()で指定した
backupsはファイルの世代数、maxLogSizeはファイルをローテートする時の最大ファイルサイズ(単位:byte)です。

ログの出力は
  1. trace()
  2. debug()
  3. info()
  4. warn()
  5. error()
  6. fatal()
とあります。
ログレベルは

var logger = log4js.getLogger(‘access_log’).setLevel(‘ERROR’);
のように指定することも可能です。

ちなみにNode.jsが標準出力するログは、上記の

{ type: ‘console’, category: ‘console’ }
で指定してあり、Node起動時に

$ node app.js >> logs/node.log
とかすれば良いです。
、、こうしないとNode.jsが吐き出すログをファイルに書き出せないです。

誰かその原因知っている人いたら教えて欲しいです。



以上でぇぇぇぇぇす。

2012年5月26日土曜日

特定のプロセスが使用しているメモリ量を監視する

どうも、俺@土曜の昼下がりです。 部屋に無理やり書斎(みたいなもの)を作ったのでとても快適です^^ さて、Linuxサーバにおいて特定のプロセスが使ってるメモリ量を調べる方法メモです。
#!/bin/sh

mem=0 #メモリ量
bef=0 #beforeの略のつもり
res=0 #結果
# 仮にapache(httpd)のメモリ量を取得する場合
while [ 1 ]
do  
    for n in `/bin/ps aux | awk '/httpd/ { print $6 }'`
    do
        mem=`expr $mem + $n`
    done
    res=`expr ${mem} - ${bef}`

    # メモリ量($mem)と前回との差分($res)を表示
    echo `date "+%F %T (${mem}) -> ${res}"`
    
    bef=$mem
    mem=0

    # 1秒ごとに処理
    sleep 1;
done
これを、apache_memorycheck.shとか名前をつけて
$ chmod +x apache_memorycheck.sh
して実行すれば 1秒ごとにapacheが使っているメモリ量と、1秒前との差分を表示できます!


$ ps axu
した結果の「RSS」の部分がプロセスが確保している物理メモリ量なので、それをawkを使って加算して計算しています。
ちなみに「VSZ」は仮想メモリ量です。(プロセス起動時にとりあえず確保される)

 以上でぇぇえぇえす。

2012年5月25日金曜日

nginxでリバースプロキシ(sslあり)

どうも、俺@華金です。

今日はnginxでリバースプロキシしちゃうぞ!(SSL付き)のメモです。
※nginx v1.2.0です。

# vim /path/to/nginx.conf
--------------------------------------
user nobody;
worker_processes 1;
events {
  worker_connections 256;
}

http {
  # この辺は環境にあわせて
  include /path/to/nginx/conf/mime.types;
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 10;

  server {
    # 1080ポートで待ち受け
    listen 1080;
    server_name koexuka.blogspot.jp;

    # ここからリバースプロキシ設定
    location / {
      # 192.168.0.10の80番ポートへリバースプロキシする
      proxy_pass http://192.160.0.10:80/

      # ヘッダ情報付与
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto http;
    }
  }

  # SSLのリバースプロキシ設定

  server {
    # 1081ポートで待ち受け
    listen 1081;
    server_name koexuka.blogspot.jp;
    # SSL設定
    ssl on;
    ssl_certificate /path/to/server.crt; # SSL証明書パス
    ssl_certificate_key /path/to/server.key; # SSL鍵パス
    ssl_session_timeout 5m;
    ssl_protocols SSLv2 SSLv3 TLSv1; # 環境にあわせる
    ssl_ciphers HIGH:!aNULL:!MD5; # 環境にあわせる
    ssl_prefer_server_ciphers on;
    # ここからリバースプロキシ設定     location / {       # 192.168.0.10の443番ポートへリバースプロキシする       proxy_pass https://192.160.0.10:443/       # ヘッダ情報付与       proxy_set_header X-Real-IP $remote_addr;       proxy_set_header X-Forwarded-Host $host;       proxy_set_header X-Forwarded-Server $host;       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       proxy_set_header X-Forwarded-Proto https;     }   } }

以上!簡単!

これでサーバの1080番ポートへのhttpパケットは192.168.0.10の80番ポートへ、
1081番ポートへのhttpsパケットは192.168.0.10の443番ポートへ送られます。



以上でぇぇえぇぇぇす。

2012年5月17日木曜日

そうだ、macvimを使おう

どうも、俺@昼休みです。
今日は、Macのテキストエディタの一つであるmacvimを使ってみたら他のどのエディタより使いやすかった、という話です。

本家はこちら
香り屋パッチがあてられて日本語化を頑張ってくれているプロジェクトはこちら



これまでmacで使うフリーのエディタに
・CotEditor(http://sourceforge.jp/projects/coteditor/
・Fraise(http://www.macupdate.com/app/mac/33751/fraise
・mi(http://www.mimikaki.net/
・テキストエディット(プリインストール)
を使ってきましたが、どれも高機能すぎたり何かの機能が足りなかったりして
「WindowsのEmEditor最強!」と思ってました。

今回どこかの記事でmacvimについて紹介されているのを読み、導入してみました。
vimは開発でよく使うエディタでとても大好きなエディタなのですが、いつもターミナル上でvimを起動して、、という使い方しかしなかったので「MacのGUIエディタで使ってみてどうかな?」と思ってましたが、、
超使いやすい!さすがvimやでぇ!
これまで使ってきたエディタなんか比にならねぇぜ。

何が使いやすいって、
・当然ながらviのキーバインド
・当然ながらファイルエンコーディングの設定とかコマンド一発
・というか、自由に~/.gvimrcに設定に書いて自分好みの環境が作れる。書き方はvimrcとほぼ同じ

:lcd <パス>
 でカレントディレクトリを移動出来る
・というか、vimで使えるコマンドは大抵使える

:!<cmd>
でmacvim上からコマンド打てる。
:!uuencode ./% hoge.txt | mail you@example.com
で編集中のファイルを添付して誰かにメール送信とか出来ちゃう。
・vimscriptが使える
・もちろん背景色やシンタックスの設定、透明度の設定もできちゃう
・タブ機能も完備
・プリンタへ送って印刷もできる
・マウスでコピペもできる
・つまり最強
という事になります。
viやvimに慣れてる人で、「macで使えるオススメのフリーエディタないかなぁ」という人には間違いなくmacvimをオススメします。

.gvimrcの例
set number
set autoindent
set sw=4
set ts=4
set ignorecase
set incsearch
set hlsearch
set statusline=%<%f\ (%05l/%05L)\ %m%r%h%w%{'['.(&fenc!=''?&fenc:&enc).']['.&ff.']'}%=%l,%c%V%8P

set laststatus=2
syntax on

set encoding=utf8
set fencs=utf8,ujis,sjis
set fileformat=unix

set transparency=5 "透明度
set lines=40 columns=180 "横幅と縦幅
colorscheme default "カラースキーム 他にもいっぱいある


以上でぇぇぇぇえす。

2012年5月11日金曜日

Objective-Cで構造体をNSLogする

どうも、俺@仕事中です。
Objective-Cで構造体をNSLogしたり、NSArrayやNSDictionaryで扱いたい場合、
例えばcocos2dのccColor3Bを

ccColor3B color = {0,0,0};
NSLog(@"%@", color);

//または
[dictionary setObject:color forKey:@"colorKey"];
のようにしてもEXC_BAD_ACCESSでエラーになります。

ここはひとつNSValueを使いましょう。
NSValue *colorValue = [NSValue valueWithBytes:&color objCType:@encode(GLubyte)];
これでインスタンス化出来る。

配列へ格納したあとの取り出しは
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:colorValue, @"key", nil];
ccColor3B color;
[(NSValue *)[dictoinary objectForKey:@"key"] getValue:&color];
とします。


以上でぇえぇぇす。

Objective-Cで 'Cannot find interface declaration for 'XXXXClass', superclass of 'ZZZZClass'...'が出る

どうも、俺@昼休みです。
タイトルの通り、Xcodeでコンパイルすると
「Cannot find interface declaration for 'XXXXClass', superclass of 'ZZZZClass'...」のエラーが出て困っていた俺へのめも。
何が起こってるかというと、簡単に言うと循環参照。

Objective-Cのクラスの前方宣言がないと困ること - アールケー開発に同じような内容の詳しい解説があります。

ClassA
#import "ClassB.h"
@interface ClassA: NSObject
{
  ClassB *b;
}
@end

ClassB
#import "ClassA.h"
@interface ClassB: NSObject
{
  ClassA *a;
}
@end
ClassAとClassBがそれぞれのヘッダファイルでお互いをimportしていて、
かつどちらかでどちらかのインスタンス変数を持っている、
またはどちらかのクラスを継承している、
ような場合にタイトルのような問題が発生します。
※コンソールからgccとかで直接コンパイルした場合は、

In file included from ClassA.h:2,
                 from ClassA.m:1:
ClassB.h:6: error: expected specifier-qualifier-list before ‘ClassA'
のようなエラーが出ます。困ったもんだ。

問題の詳細はコンパイルの処理にあり、
■ClassA.hのコンパイル
ClassA.h内で#import "ClassB.h"が見つかった時点でClassB.hをインポート(解析)する。
ClassB.h内にある#import "ClassA.h"が見つかりClassA.hをインポート(解析)するはずだが、#import宣言はネストしながらインポートしないため、実際はClassA.hのインポートは行われない。
ClassB.h内のClassAインスタンス変数の定義(ClassA *a;)で、ClassAの宣言が見つからないのでエラーとなる。
、、、そうです。

こういうような場合、#import宣言をやめて@classを使い前方宣言で対処できるのであればそれで解決できます。

ClassA
@class ClassB;
@interface ClassA: NSObject
{
  ClassB *b;
}
@end

ClassB
@class ClassA;
@interface ClassB: NSObject
{
  ClassA *a;
}
@end


ただし、対象のクラスを継承していたり、処理内で対象のクラスをallocしたりしてる場合は#importを使わなければいけません。


以上でェェエェす。


macでlsしたときの@(アットマーク)

どうも、俺@今から仕事です。
Mac(Tiger以上)のターミナル上で

$ ls -l
したときにファイルやディレクトリの属性に@(アットマーク)が付いている場合があります。

$ ls -l
-rw-r--r--   1 username  staff    411 12 12 17:44 hoge.txt
-rw-r--r--   1 username  staff  26945  5 11 09:39 foo.txt
-rw-r--r--@  1 username  staff   1766  5 11 09:37 fuga.txt #←こいつ!

なんだこれは?ということで調べてみると、Mac Tigerで導入されたファイルリソース(Extended Attributes)というものらしいです。
※Tigerではデフォルトで無効化されており、実質Leopardから見られる。

拡張属性というもので、Spotlightなどの検索で利用されるらしい。
特にその存在が邪魔するというともないとは思いますが、「きもい!消したい!」という人(俺)は、
1)まず確認
$ ls -l@
-rw-r--r--   1 username  staff    411 12 12 17:44 hoge.txt
-rw-r--r--   1 username  staff  26945  5 11 09:39 foo.txt
-rw-r--r--@  1 username  staff   1766  5 11 09:37 fuga.txt
        com.apple.metadata:kMDItemWhereFroms      174
        com.apple.quarantine       70
lsに-@を付けることでその詳細が確認できます。
ここにある、com.apple.metadata:kMDItemWhereFromsとcom.apple.quarantineはダウンロードしたファイルにつく属性みたい。
$ xattr -d com.apple.metadata:kMKItemWhereFroms fuga.txt
$ xattr -d com.apple.quarantine fuga.txt
これで削除できます。

以上でぇぇぇぇえぇぇぇぇえす。

2012年5月10日木曜日

objective-cのクラスでプロパティをprivateに

どうも、俺@残業中です。
今日はObjective-Cのクラスで、プロパティ(@property)宣言した値をprivateのように扱う方法めもです。

MyClass.h
@interface MyClass {

  // インスタンス変数
  NSString *string;
}
@end

MyClass.m
#import "MyClass.h"
// 無名カテゴリ宣言
@interface MyClass()
@property (nonatomic, retain) NSString *string;
@end

@implementation MyClass
@synthesize string;
@end
これでオッケー。

ヘッダファイルにプロパティを書いてしまうと、外部からそのプロパティにアクセス出来てしまうことが用意に想像できてしまい、意識せずに外部からそのプロパティへアクセスしてしまいがちです。
プログラマが一人であったり、小規模なプロジェクトであれば問題ありませんが、「このインスタンス変数は外部からアクセスしちゃあかんでぇ」と意識させたい場合などにはこの方法が便利です。

ただし、Objective-Cの特性で外部からのアクセスを完全に遮断することは出来ず、やろうと思えばアクセス出来ちゃいますが、こればかりはどうしようもありません。あしからず。


以上でぇぇぇぇえぇす。

2012年4月30日月曜日

php-fpmで”Starting php-fpm .... failed"になる

どうも、俺@連休満喫中です。
今日はphp-fpmを起動させたときに起こったトラブルシューティングです。

phpv5.4.1をソースからインストールし、php-fpmの起動スクリプトを/etc/init.d以下へ設置します。

# cp php-5.4.1/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
# chmod +x /etc/init.d/php-fpm

これで起動させます。

# service php-fpm start
Starting php-fpm .................................... failed
Oh!No! 起動失敗かよ!
と思いきや、psコマンドで見るとphp-fpm動いてる。

# ps axuw -H

root     26983  0.0  0.3  98380  4056 ?        Ss   00:53   0:00   php-fpm: master process (/usr/local/php-5.4.1/etc/php-fpm.conf)                    
nginx    26984  0.0  0.4  98380  4412 ?        S    00:53   0:00     php-fpm: pool www                                                                  
nginx    26985  0.0  0.4  98380  4420 ?        S    00:53   0:00     php-fpm: pool www   

コンソール上では起動失敗しているように見えますが、php-fpmプロセスは起動しています。なのでこのままでも動作はしますが毎回起動する度にエラーが出るので気持ち悪いです。
多分ですが、起動後にpidファイルの生成がうまくいかずエラー表記になってるみたいです。今度調べとかないと。。

なんて状況で困っているあなた。

調べてると、
http://serverfault.com/questions/195966/php-fpm-getting-a-failed-message-but-the-processes-start-ok
に答えがありました。
php-fpm.confファイルにあるpid fileに関するディレクトリがコメントアウトされているので「;(セミコロン)」を外せば良いようです。


# vim /path/to/php-fpm.comf
-----------------------------------------

 25 ;pid = run/php-fpm.pid
 26 pid = run/php-fpm.pid
これでよし。

これで起動させれば、問題なく起動できます。


以上でぇぇぇえす。



2012年4月6日金曜日

[Node]expressで”Cannot find module ‘express’が出る

どうも、俺@寝る前です。
前回の内容とかぶるのですが。


開発スピードの超早いNodeですが、あまりにも早過ぎるため開発中にどんどん新しいバージョンがリリースされてしまいます。
流行りもの好きな人にとっては居ても立ってもいられない状況であり、それを解決するためのツールの一つにnaveがあります。
もはや説明するまでもなく、Nodeのバージョン管理ツールです。

今日はnaveを使ってタイトルのようなエラー、または他にもNodeで使うはずのモジュールが「Cannot findだぜ!」となる人へ。

$ node app.jp
node.js:12
throw e; / process.nextTick error, or ‘error’ event on first tick
^
Error: Cannot find module ‘express'

要は環境変数NODE_PATHに対し、正しくNodeモジュール群のパスを示せれば良いので、

export NODE_PATH=/path/to/node_modules
とすれば良いのですが、
「/path/to/node_modulesってどこだよっ!?」って人は、
naveをインストールしたディレクトリを起点に

[naveインストールディレクトリ]/installed/[バージョン番号]/lib/node_modules
にあります。

これで解決なのですが、毎回 export 打つのは面倒です。なので、

$ vim ~/.zshrc
---------------------------------
export NODE_PATH=/path/to/node_modules
としても良いのですが、.zshrcにハードコーディングするとバージョンが変わるたびに.zshrcを書き換えなければいけません。
そこで、もう一つの代案として、

$ vim /path/to/nave.sh
-----------------------------------
# nave_use()を探して、その関数内にある
local lib=“$prefix/lib/node:$prefix/lib/node_modules
と変更する方法でも良いです。
ちなみにnave.shは僕の環境だと

$ ls -la ~/.nave

合計 116
drwxr-xr-x 5  koexuka groupname  4096  3月  6 00:21 .
drwxr-xr-x 6 koexuka groupname  4096  3月  6 00:16 ..
drwxr-xr-x 8 koexuka groupname  4096  3月  3 14:33 .git
-rw-r--r-- 1 koexuka groupname    14  3月  3 14:33 .gitignore
-rw-r--r-- 1 koexuka groupname    14  3月  3 14:33 .npmignore
-rw-r--r-- 1 koexuka groupname     9  3月  3 17:24 .zshenv
-rw-r--r-- 1 koexuka groupname   248  3月  3 14:33 AUTHORS
-rw-r--r-- 1 koexuka groupname  4002  3月  3 14:33 README.md
drwxr-xr-x 4 koexuka groupname  4096  3月  4 15:04 installed
-rwxr-xr-x 1 koexuka groupname 12918  3月  4 15:06 nave.sh
-rw-r--r-- 1 koexuka groupname   345  3月  4 15:02 naverc
-rw-r--r-- 1 koexuka groupname   197  3月  3 14:33 package.json
drwxr-xr-x 3 koexuka groupname  4096  3月  4 15:04 src
にあります。

以上でぇぇぇぇぇぇす。

2012年4月3日火曜日

zshでnaveを使うと"no such option: rcfile"が出る

どうも、俺@仕事中です。
nodeのバージョン管理をnaveを使って優雅に使いこなそうとして

$ ./nave.sh use stable
とかカッコ付けてやると

$ Already installed: 0.6.14
using 0.6.14
/bin/zsh: no such option: rcfile
とか出て「マジでか!?」ってなる人へ。

nave use latest: zsh no such option rcfile - Linux LABS
にあるように実行ユーザのシェルをbashに変えちゃうという方法もありますが。

nave.shを見てみると
$ vim nave.sh

-------------------------------
408: "$SHELL" --rcfile "$NAVE_DIR/naverc"
〜(中略)〜
464: "$SHELL" --rcfile "$NAVE_DIR/naverc"
と2ヶ所rcfileオプションを使ってる場所があります。
そもそもrcfileオプションはbashで使えるオプションで、コマンドラインでシェルを使う場合に設定ファイルとして読み込むファイルを指定できるオプションです。
つまり上記のnave.shでは

 bash --rcfile ~/.nave/naverc
のように"~/.nave/naverc"を読み込んで対話型bashを使う、というようにプログラムされているのですが、
実行ユーザのシェルがbash以外だと$SHELLがzshなりtcshなりに展開されて、意図しない動きになっちゃう訳です。

僕が普段使うzshは--rcfileというオプションが使えません。
基本的にログイン時は

$ZDOTDIR/.zshenv $ZDOTDIR/.zprofile $ZDOTDIR/.zshrc $ZDOTDIR/.zlogin
これらのファイルが読み込まれるのですが、全部が全部ログイン時に読み込まれるわけではなく、詳しくは
zsh - watallica metallicus
を参照のこと。

今回は .zshrc に設定することにします。
# 以下の方法は正しい動作を保証するものではありません。
# とりあえず動くように設定していますので、安定性を重視する場合は実行ユーザのログインシェルをbashにしておき、配布されたソースプログラムは変更しない事をお勧めします。

という訳で、書き換えちゃいましょう。
$ vim nave.sh

-------------------------
# nave_use () 内
397: else
398:   hash -r
399:   NAVELVL=$lvl NAME="$version" ¥
400:     NAVEPATH="$bin" ¥
401:     NAVEVERSION="$version" ¥
402:     NAVENAME="$version" ¥
403:     npm_config_binroot="$bin" npm_config_root="$lib" ¥
404:     npm_config_manroot="$man" ¥
405:     npm_config_prefix="$prefix" ¥
406:     NODE_PATH="$lib" ¥
407:     NAVE_LOGIN="1" ¥
408:    "$SHELL"
409: #"$SHELL" --rcfile "$NAVE_DIR/naverc"

コレでよしと。

次にnave用のzshが起動されたときの処理を.zshrcに書きます。
$ vim ~/.zshrc
------------------------------------
# 追加
if [ "$NAVE_LOGIN" = "1" ]; then
    export PATH=$NAVEPATH:$PATH
fi


これで準備完了です。
あとは優雅に

$ nave.sh use stable
と打つべし。


以上でぇぇぇえぇぇす。





gccのバージョンを確認する方法

どうも、俺@昼休みです。

インストールされているgccのバージョンを確認したい場合は

$ gcc -dumpversion
3.4.5
で確認できます。
ちなみにv3.4.5は非常に古いバージョンですが、僕の開発サーバではこのバージョンでgcc使ってます。


以上でぇぇぇぇぇえす。

2012年3月23日金曜日

CGRect、CGSize、CGPointについて

どうも、俺@絶賛開発中です。
今日は(も)Objective-Cについてです。最近はアプリ(iOS/Android)関連の仕事が多いですね。

Objective-Cで開発してるとよくCGRectやCGPoint、CGSizeなどといったクラス(構造体)を使います。
これについてメモメモ。
ゲームアプリなど座標を細かく管理する開発では必須の知識です。

■CGRect
オブジェクトの座標とサイズを管理します。
// 座標(100, 100)の位置に横50 x 縦50のサイズを表すCGRect
CGRect rect = CGRectMake(100, 100, 50, 50);


■CGPoint
オブジェクトの座標を管理します。
//座標(200, 100)の位置を表すCGPoint
CGPoint point = CGPointMake(200, 100);


■CGSize
オブジェクトのサイズを管理します。
// 横200 x 縦100のサイズを表すCGSize
CGSize size = CGSizeMake(200, 100);


またこれらをコンソール上にログ出力する場合は、

CGRect rect = CGRectMake(0, 0, 30, 30);
NSLog(@"%@", rect);
のようにしても出力されません。

座標情報やサイズをログ出力させるには、
NSStringFromCGRect()
NSStringFromCGPoint()
NSStringFromCGSize()
これらを使います。

CGPoint point = CGPointMake(100, 200);
NSLog(@"%@", NSStringFromPoint(point));


以上でぇぇぇえぇす。

2012年3月13日火曜日

NSStringのstringByAppendingPathComponent注意

どうも、俺@仕事中です。
Objective-Cでゲームとか開発してると、ユーザのちょっとしたデータをファイルに保存したりしますよね。

その時のコードでエラー起こしてしまったので、対処法をメモ。

間違いソースがこれです。

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex: 0];
self.filePath = [directory stringByAppendingPathComponent: @"hoge.plist"];
self.filePathは保存するファイルのパスを格納するNSStringなクラス変数です。

これだとstringByAppendingPathComponentメソッドは結果をautoreleaseしている(と思う)ので、
ココの処理を抜けた時点でself.filePathはリリースされてしまう(はず)。
別のメソッドでself.filePathを使おうとしても、リリースされたオブジェクトにアクセスしようとしてEXC_BAD_ACCESSになっちゃう。


NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex: 0];
self.filePath = [[NSString alloc] initWithString: [directory stringByAppendingPathComponent: @"hoge.plist"]];
にしてやれば、self.filePathを自身のdeallocメソッド内でreleaseすることが出来る!


以上でぇぇえぇす。

2012年3月6日火曜日

Autoingestion.classを使うとjavax.net.ssl.SSLHandshakeExceptionが出ちゃう

どうも、俺@残業中です。

iPhoneアプリの販売データを取得するため、AppleはAutoingestion.classなるものを用意してくれてます。
iTunesConnectのSales and TrendsにあるデータをTSVデータとしてDLできます。
わざわざHTMLをスクレイピングしなくて良いですね!
ドキュメントはココ
とても分かりやすい参考サイトは iTunesConnectからアプリダウンロード数レポートを自動取得する方法 - zaru blog がとても分かりやすいです!

ところが、僕の開発環境だと、このプログラムを実行させるとタイトルの通り

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
になっちゃいます。ほとんどの人は関係ないと思いますが。。
今日はその解決法をばめもめも。

javaのkeytoolというコマンドを使って、証明書をインポートすれば良いそうです。
あまりjavaには明るくない俺なりに調べてみたのですが、
どうやら[SSLHandshakeException]信頼できない証明書のサイトと無理矢理接続する方法にあるように、
Javaで信頼できないSSL証明書を使ってHTTPコネクションを貼ろうとした場合に出る例外のようです。
AppleからのAutoingestion.classがどういう実装になっているのか調べてみれば分かるかもしれませんが、
とりあえず今回は解決優先ということで、「Sales And Trends」データを取得しにいくサーバへSSL通信するときの証明書が怪しいのでは?という仮説を立てて対応することにしました。

つまり、接続先の証明書をkeytoolを使ってインポートすれば良いのです。
証明書はhttps://itunesconnect.apple.comのものだと思います。
つまり、Autoingestion.classはitunesconnect.apple.comへ接続しにいっているはず。
(多分。。。tcpdumpとかでパケットを監視してないので嘘だったらごめんなさい。今度調べます。)

なので、FireFox(僕Mac版FireFox使ってます)とかで上記URLを叩き、
アドレスバーの左側(緑色になっているはず)をクリック>詳細を表示>「セキュリティ」タブ>証明書を表示...>「詳細」タブ>書き出す...
の操作を行えば証明書を取得できます。

この証明書ファイルを、開発サーバのjavaへ組み込みます。

$ keytool -import -keystore /usr/local/jdk1.6.0_16/jre/lib/security/cacerts -storepass changeit -file /path/to/証明書ファイル
これでOK。
-keystore は俺の環境での値を書きましたが、環境に合わせて書き換えて下さい。
-storepass はデフォルトでchangeitです。
-file は先程FireFoxから取得した証明書ファイルへのパスです。
何とこれでサーバのjava(/path/to/jdk/jre/lib/security/cacerts)に証明書データがインポートされ、
「信頼できる証明書」として扱われます。
オレオレ証明書を作成した場合などで使えますね!

keytoolについてはJava/keytool - 備忘録に詳しく書かれています。


これでAutoingestion.classを使えば、悩み解決されます!

$ java -cp . Autoingestion username password vendorid Sales Daily Summary `date +%Y%m%d -d "2 days ago"`

.gzファイルがDLされます!

以上でぇぇぇえぇす。

2012年3月3日土曜日

無料iPhoneアプリ「なむぞう」リリースしました!

どうも、俺@スノボから帰ってきました。
今回はちょっと技術ネタから外れますが。。。

さてさて、やっとiPhoneアプリ「なむぞう」をリリースすることができました^^

http://itunes.apple.com/jp/app/namuzou/id499190444?mt=8







デザインも自分で担当したため、オシャレなUIとまではなりませんでしたが
配色サンプルを色々試して何回も試行錯誤しながらUI全体の色イメージをつくっていきました。

あと、どうでも良いですが
アイコン画像にいるイモムシのようなやつが「なむぞう」というキャラクターという設定です。


リリース直後にGameCenterにつながらない不具合が見つかったり、その他色々。。。。
初めてのアプリ開発で色々戸惑いも多かったですが、もう大丈夫です!!


紹介動画です^^
http://www.youtube.com/watch?v=yxUu9crJtas
動画編集ソフトやYoutubeの機能を駆使してつくりました!


Objective-Cについて、色々とスキルを身につけられましたが
それと同様にドローソフトや動画編集ソフトの使い方に詳しくなれました。



以上でぇぇぇぇす。

2012年2月9日木曜日

NSLocalizedStringとstringWIthFormatを使ってiPhoneアプリの多言語化

どうも、俺@仕事中です。
今日はiPhoneアプリをNSLocalizedString()とNSString stringWithFormatを使って多言語対応する方法のめもめもです。

日本語環境のみに作ったアプリを
NSString *str = @"にほんご";
英語圏で使うようにするには

NSString *str = NSLocalizedString(@"key", @"comment");
としておき、ターミナルから

genstrings -a $(find ./ -name "*.m");
とすればLocalizable.stringsファイルができるので、Xcode内にドラッグ&ドロップ(Xcode4では「Supporting Files」が適当かな)します。
Localizable.stringsはUtilitiesのFile Inspectorから作成する言語とText−Encoding(UTF-16)を設定します。
Localizable.strings内では
・Localizable.strings(English)
"key" = "Japanese;"

・Localizable.strings(Japanese)
"key" = "にほんご"
としておけば、"key"と記述した部分をそれぞれの言語に変更してくれます。
※ここでは"Japanese"と"にほんご"に置換してくれる。

これら詳しい説明は
NSLocalizedStringでiphoneアプリ多言語対応 Xcode4 - はるかなる熊がとても参考になりました。


ところで、英語と日本語では文法的に単語の出てくる順番が異なるときが出てくる。
例えば
私は「テトリス」で「100」pt取った。
という日本語を英語にすると
I took 「100」pt in 「Tetris」.
となる。「」で囲まれた単語が異なる場合がある。
こういう場合、まずobjective-cのソースコードでは英語に合わせて作ったほうが分かりやすい。

NSString *str = [NSString stringWithFormat: NSLocalizedString(@"long sentence", @"some comment"), @"100", @"Tetris"]
こうしておいた上で、それぞれのLocalizable.stringsでは
・Localizable.strings(English)
"long sentence" = "I took %d pt in %@.";

・Localizable.strings(Japanese)
"long sentence" = "わたしは%$2@で%1$d取った。";
とする。
stringWithFormat の%$n@でフォーマットに入れる変数の順番を変更できるのです。(nは整数)


以上でぇぇぇぇぇぇす。

2012年1月31日火曜日

Xcode 実機で動作しなくなる('NSInternalInconsistencyException', reason: ' Could not load NIB in bundle...)

どうも、俺@絶賛objective-c中です。

Xcode ver.4.2で開発してて、iPhoneシュミレーターでは動作確認できるのですが急に実機で動作しなくなった!という場合の対処法めもです。
場合によっては原因が異なると思うので、これが解決法の全てではないかもしれませんが。。

iPhone実機(5.0.1)に繋いでXcodeからビルド&実行すると以下のようなエラーが出てしまい、ビルドはできるのですが実行できません。

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle (loaded)' with name 'ViewController'
つい5分前までは動いてたのに!
原因はよく分かりませんでしたが、以下をやることで実機でも動作するようになりました。

エラーログにある「ViewController.xib」を開き、右側の「Utilities」>「File Inspector」内にある「Localization」の部分を見ます。
僕の場合は
English
の1つのみが書かれていたので、「Japanese」を追加します。

するとViewController.xibが
ViewController.xib(English)
ViewController.xib(Japanese)
の2つになります。
この状態で実機転送すると動作します。

このあと、なぜか先ほどのLocalizationにある
Japanese
は削除しても実機で動作しちゃいます。

理由はよくわかりませんが、もしトラブった人は試してみて下さい。


以上でぇぇぇぇぇぇす。

UIViewアニメーションで一時停止

どうも、俺@コーディング中です。
今日はObjective-Cでアプリ開発をしてて、UIViewのアニメーションを使うことはよくあるのですが、今日はそのアニメーションを一時停止させる方法をめもめもします。
// hogeLabelの座標は(0, 0)
hogeLabel.frame = CGRectMake(0, 0, 100, 100);

// アニメーション開始
[UIView beginAnimations:nil context:nil];

// アニメーション時間
[UIView setAnimationDuration:1.0f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];

// hogeLabelを(200, 200)の位置へ動かす
hogeLabel.frame = CGRectMake(200, 200, 100, 100);

[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(hogeLabelStopped:finished:context:)];
[UIView commitAnimations];
とりあえずこれでhogeLabelは座標(0, 0)から(200, 200)へ1秒かけて動くアニメーションができました。
このあとセレクターメソッド(hogeLabelStopped)内で、一旦停止させるには

- (void)hogeLabelStopped:(NSString *)animation finished:(BOOL)finished context:(void *)context
{
  // 一時停止(0.5秒)
  [NSThread sleepForTimeInterval:0.5];

  // その他の動作はこれ移行に記述
}
こんな感じです。[NSThread sleepForTimeInterval:(double) interval]はスレッドをsleepさせる静的なメソッドです。

以上どっぇぇぇぇぇえっぇぇす。

2012年1月20日金曜日

UIViewのアニメーションで画面遷移

どうも、俺@仕事中です。久々のObjective-Cです。
アプリでUINavigationControllerを使わずに画面をアニメーションさせて遷移させる方法を調べたのでメモメモ。

右から左へスライドインする処理
■元画面(FirstView: UIVIewControllerを継承)
// 遷移先UIViewを画面外に生成(SecondView: UIVIewを継承)
secondView = [[SecondView alloc]initWithFrame:CGRectMake(self.view.frame.size.width + 1, 0, self.view.frame.size.width, self.view.frame.size.height)];

// アニメーション開始
[UIView beginAnimations:nil context:nil]:
[UIView setAnimationDuration:0.5]; // 0.5秒かけて
[UIView setAnimationCure:UIViewAnimationCurveLinear]; // 一定速度で
[self.view addSubview:secondView]; // addSubviewする

secondView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); // 画面内へ動かす
[UIView commitAnimations]; // アニメーションコミット
これで右から画面内へスライドインする遷移ができます。

今度は戻るボタンなどで元画面へ戻る処理です。
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveLInear];
[UIView setAnimationDelegate:self]; // デリゲートをselfで指定
[UIView setAnimationDidStopSelector:@selector(animationStopped:finished:context:)]; // アニメーションが完了した時の処理

secondView.frame = CGRectMake(self.view.frame.size.width + 1, 0, self.view.frame.size.width, self.view.frame.size.height); // 画面外へ
[UIView commitAnimations];
/**
 * アニメーション停止後の処理
 */
- (void)animationStopped:(NSString *)animation finished:(BOOL)finished context:(void *)context
{
  [secondView removeFromSuperview]; // secondViewをremoveFromSuperviewする
}
こうなります。
secondViewをremoveFromSuperviewする場合は、UIViewのsetAnimationDidStopSelectorを使ってアニメーション停止後の処理をセレクターを使って処理させて下さい。そうしないとアニメーションが動きません。
またその場合はUIViewのsetAnimationDelegateメソッドを呼んでおく必要があります。
以上でぇぇぇぇぇぇす。

2012年1月5日木曜日

lsattrとchattrコマンド

明けましておめでとうございます。本年もよろしくお願い致しMuscle!
俺@今日から仕事始めです。

Linuxで削除できないファイルがある、または削除できないファイルを作るなどといった場合に使えるコマンドの紹介です。
これはext2またはext3ファイルシステムで使える、固有のフラグを操作するコマンドです。

chattrコマンドで操作できます。

$ chattr +i hoge.txt
これでhoge.txtは、たとえrootユーザになって削除しようとしても

# rm -rf hoge.txt
rm cannot remove `hoge.txt': Operation not permitted
となります。

このi属性を削除するには

$ chattr -i hoge.txt
でOKです。
引数に「+」で属性追加、「-」で属性削除になります。
操作できる属性は

・a...ファイルの追書き込みのみ許可(append)
・c...ファイルを圧縮しディスクに保存する(compress)
・d...dumpコマンドによるバックアップ候補にしない(dump)
・i...ファイル変更を許可しない。rmやmvができない(immutable)
・A...ファイルがアクセスされた時のatimeを更新しない。Disk I/Oが少し早くなるかも?
・D...ディレクトリに変更があった場合、すぐディスクに保存する。
・S...ファイルに変更があった場合、すぐディスクに保存する。
です。他にもありますが、、
実際使えるとすれば「i」と「A」かな。

任意のファイルの属性を確認するには

$ lsattr hoge.txt
で、上記のフラグのいずかが出ればその属性が立っているということ。
何もなければ(普通ないが)
------------- hoge.txt
となります。


少々マニアックなコマンドですが、プログラムで「何が何でも消してはアカンファイルがある!」という場合など、使えるかもしれません。
また、不正プログラムなどにはこの属性がしてされており、もし管理者が不正ファイルを見つけて消そうとしても簡単には消えないようにされている場合もあります。


以上でぇぇえぇぇす。