2013年12月4日水曜日

[cocos2d-x] CCSpriteの画像を切替える

どうも、俺@眠いです。

CCSpriteのテクスチャ画像をA→Bへ切り替える方法をメモ。


// まず最初の画像 a.png
CCSprite *aSprite = CCSprite::create(“a.png”);

// b.pngへ切り替える
aSprite->setTexture(CCTextureCache::sharedTextureCache()->addImage(“b.png”));
aSprite->setTextureRect(CCRectMake(0,0,aSprite->getContentSize().width, aSprite->getContentSize().height));

もしCCSpriteFrameCacheやCCSpriteBatchNodeを使っている場合は、
// 何らかのスプライトシート
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(“a.plist”, “a.png");

// 最初の画像 a.png
CCSprite *aSprite = CCSprite::createWithSpriteFrameName(“a.png”);

// b.pngへ変える
CCSpriteFrame *spriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(“b.png”);
aSprite->setDisplayFrame(spriteFrame);

以上でぇぇぇぇぇす。

2013年11月17日日曜日

L7ロードバランサHaproxyを使う(その3 syslogの設定とコマンドラインツール)

どうも、俺@眠いす。


今日は「L7ロードバランサHaproxyを使う(その2 設定から起動)」の続きです。
前回では、haproxy.cfgを編集してリクエストに応じて
バックエンドサーバを切り替える(Proxyする)ところまでやりました。
※サーバはCentOS6.xです。

今日はその設定にあった
1)ログ出力
2)haproxy状態を確認するコマンドラインツール
の使い方を書きます。


1)ログ出力
前回の説明で、haproxy.cfg設定に
log         127.0.0.1 local6 debug

というのがありました。
これはHaproxyのログを書き出す設定、というところまで説明しましたが、
今回はもう少し具体的に解説します。

syslogにログを出力させるために、まず /etc/syslog.confを開き、
# add haproxy setting
local6.* /var/log/haproxy_log
を追加します。
facility(local6)に設定した出力を/var/log/haproxy_logに書き出す、という意味です。
この書式は
(facility).(priority) (action)
です。
上の場合は、local6ファシリティの全てのpriorityを/var/log/haproxy_logに出力となりますが、
もし出力レベルを変えて「警告以上のみを出力」としたい場合などは
# add haproxy setting
local6.warn /var/log/haproxy_log
とすると良いでしょう。
または、haproxy.cfgの「debug」を「warn」に変えるという方法でも良いです。

次に、/etc/sysconfig/syslogを編集します。
SYSLOGD_OPTIONS="-m 0 -r"
そしてsyslogdを再起動。
service syslogd restart
これでログ出力完了(のはず)です。


2)haproxy状態を確認するコマンドラインツール
これは前回haproxy.cfgに設定した、
  # 統計情報が見れる。※ただし要設定!次回説明します。。
  stats socket /var/run/haproxy/stats.socket uid 105 gid 105 
の部分です。
コマンドラインからhaproxyのステータス情報を確認できるようになります。
まず、socatというツールをインストールします。
yum install --enablerepo=epel socat
haproxyを再起動します。
service haproxy restart

あとは、socatを使い情報を取得します。
// 一般的な情報を出力
echo "show info" | socat unix-connect:/var/run/haproxy/stats.socket stdio

// エラー情報を出力
echo "show errors" | socat unix-connect:/var/run/haproxy/stats.socket stdio

// 統計情報を出力
echo "show stats" | socat unix-connect:/var/run/haproxy/stats.socket stdio
のような感じです。
hastats(ステータスページ)では確認できないような詳細なデータを見ることが出来ます。



以上でぇぇぇぇぇす。

2013年11月7日木曜日

L7ロードバランサHaproxyを使う(その2 設定から起動)

どうも、俺@仕事中です。


L7ロードバランサHaproxyを使う(その1 インストールまで)」の続きです。
前回では、
 Haproxyのインストール
 起動スクリプトの設置
 起動確認
 デフォルトの設定ファイル(ひな形)のコピー
まで行いました。
今回は設定ファイルを編集して、ロードバランサ(またはProxy)として動かしてみます。

では、設定ファイルを開きます。
vim /etc/haproxy/haproxy.cfg
ひな形としてすでに何か書かれていると思います。
設定ファイルは大きく分けて5つのセクションから成っています。

1.globalセクション
 全体の挙動に関する設定を行う。

2.defaultsセクション
 以下の「listen」「frontend」「backend」に関するデフォルトの設定を行う。

3.listenセクション ※必須ではない
 frontendやbackendの設定をこのセクションでまとめて行える。
 または、hastatsというステータス情報を出力するページの設定を行う。

4.frontendセクション
 クライアントからのパケット受け入れに関する設定を行う。

5.backendセクション
 ロードバランス(またはProxy)するサーバ(群)に対する設定を行う。


では、簡単に見ていきます。
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # ログの出力 ※次回説明します。。
    log         127.0.0.1 local6 debug

    # pidファイルのパス
    pidfile     /var/run/haproxy.pid

    # 1プロセスに対する最大接続数
    maxconn     4096

    # 実行ユーザとグループ
    user        haproxy
    group       haproxy

    # 起動プロセスはバックグラウンドで動作します。。
    daemon

    # 起動するプロセス数。公式には'1'のままで良いとのことですが、16コアCPUだと4くらいが最もパフォーマンスが出た。。
    nbproc 2
 
   # プロセスごとの最大ファイルディスクリプタを設定。書かなくても自動で設定されるらしい。
    ulimit-n 12000

    # 統計情報が見れる。※ただし要設定!次回説明します。。
    stats socket /var/run/haproxy/stats.socket uid 105 gid 105 
次に、defaultsセクション。
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will 
# use if not designated in their block
#---------------------------------------------------------------------
defaults
   # L7でロードバランス。'mode tcp'とすればTCPレベル(L4)でロードバランスするので処理速度の向上が見込める。
    mode        http 

    # globalセクションでの設定が引き継がれる。
    log         global

    # このオプションよう分からん。。NULLなコネクションのログを書き出さない?
    option      dontlognull

    # ヘルスチェックのログを書き出す。
    option      log-health-checks

    # backendサーバに接続できない時のタイムアウト秒数(ミリ秒)
    timeout connect 10000 # default 10 second time out if a backend is not found
    # クライアントサイドでのタイムアウト秒数。' timeout server 'と同じ値が推奨とのこと。
    timeout client  30000
    # サーバサイドのタイムアウト秒数
    timeout server  30000

    # 接続に失敗した際のリトライ回数
    retries     3

次はlistenセクション。僕はhastats(ステータスページ)で使っています。
# 8088ポートで待受ける
listen hastats *:8088
    mode http
    maxconn 64
    contimeout 5000
    clitimeout 10000
    srvtimeout 10000
    stats enable
    stats show-legends
    stats uri /haproxy?hastats

    # IDとパスワード
    stats auth username:yourpassword
これで、http://example.com/haproxy?hastatsを入力するとHaproxyのステータスが表示される

次にfrontendセクション。
# 80番ポートで待ち受ける。
frontend  all 0.0.0.0:80
    # URLの最初に/static /images /javascript /stylesheetsがあれば url_static をTRUEに設定する。
    acl url_static       path_beg       -i /static /images /javascript /stylesheets

    # URLの最後が .jpg .gif .png .css .jsだったら url_static をTRUEに設定する。
    acl url_static       path_end       -i .jpg .gif .png .css .js

    # もし url_staticがTRUEだったら、バックエンドは static を使う。
    use_backend static          if url_static

    # デフォルトのバックエンドは app を使う。
    default_backend             app
このACLがhaproxyの強みで、いろんな条件に応じてバックエンドサーバを振り分けることが可能です。
※ACLについては「HAProxyのACLとCriteria」が詳しかったです。またはここのGoogle Docs。
URLやIPアドレス、ポート、HTTPヘッダなどを見て振り分けられます。

次にbackendセクション
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
# static というバックエンドサーバ
backend static
    # ラウンドロビンでの振り分け(デフォルト)。比重の設定も可能。
    balance     roundrobin

    # 127.0.0.1:4331で起動。IPを変えて他サーバにすることが可能。
    # checkでヘルスチェックを有効にする。
    server      static 127.0.0.1:4331 check

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
# app というバックエンドサーバ群
backend app
    # ラウンドロビンで振り分け。
    balance     roundrobin

    # サーバは以下の4台でラウンドロビン。ちなみに weight '数値' とすることで振り分けの比重を設定できる。
    server  app1 127.0.0.1:5001 check
    server  app2 127.0.0.1:5002 check
    server  app3 127.0.0.1:5003 check
    server  app4 127.0.0.1:5004 check
こんな感じです。


これで起動させてみましょう。
service haproxy start
URLの末尾が xxx.jpg とかだと、きっと127.0.0.1:4331へProxyされるはずです。


ちょっと長くなったのでログ出力と'stats socket'についてはまた次回書きます。


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


※2013.11.16追記
L7ロードバランサHaproxyを使う(その3 syslogの設定とコマンドラインツール)」書きました。

2013年10月24日木曜日

[cocos2d-x] 画面サイズ、ウインドウサイズについて

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

cocos2d-xでは画面の表示領域を取得するメソッドがいくつかありますが、
いつも混乱するのでまとめておきます。

・端末の解像度ごとのサイズを取得する(フレームサイズ)

// 幅
float width = CCEGLView::sharedOpenGLView()->getFrameSize().width;
// 高さ
float height = CCEGLView::sharedOpenGLView()->getFrameSize().height;
これで、実際の端末解像度の値が取得できます。
例えば縦型(ポートレイト)の場合、heightはそれぞれ、、
iPhone4S...960
iPhone5...1136
iPhone5S...1136
iPad(非retina)...1024
iPad(retina)...2048
となります。
Android端末の場合は、それぞれの端末ごとの解像度になります。


・setDesignResolutionSize()している時の表示サイズを取得する(ウインドウサイズ)

// 幅
float width = CCDirector::sharedDirector()->getWinSize().width;
// 高さ
float height = CCDirector::sharedDirector()->getWinSize().height;

// または
// 幅
float width = CCEGLView::sharedOpenGLView()->getDesignResolutionSize().width
// 高さ
float height = CCEGLView::sharedOpenGLView()->getDesignResolutionSize().height;
これで、解像度に合わせて画面サイズを設定している場合の幅、高さが取得できます。



以上でぇぇぇぇぇえす。

2013年10月21日月曜日

Linuxカーネルが32bitか64bitか、またCPUが64bit対応か32bit対応かを確認する

どうも、俺@帰る前です。

L7ロードバランサHaproxyを使う(その1 インストールまで)を書いてて、調べる機会があったのでまとめておきます。

・Linuxが32bitカーネルか64bitカーネルかを調べる

uname -a
Linux centos 2.6.18-238.9.1.el5 #1 SMP Tue Apr 12 18:10:13 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux
のように、x84_64が出てくると64bitカーネルです。
32bitカーネルの場合は

uname -a
Linux centos 2.6.18.8-xenU #4 SMP Fri Sep 26 11:41:46 JST 2008 i686 unknown
のように、i686やi386が出ます。


・CPUが32bitアーキテクチャか64bitアーキテクチャかを調べる

cat /proc/cpuinfo | grep lm
flags           : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx lm up pni vmx cx16 popcnt lahf_lm
のように、flagsに「lm」が出てくれば64bitアーキテクチャ。
ちなみにlmは「ロングモード(x86_64)」の略のようです。
32bitのCPUでは「lm」が出てきません。

※参考「/proc/cpuinfo 再調査編 - ぴろにっき


以上でぇぇぇぇぇえす。

L7ロードバランサHaproxyを使う(その1 インストールまで)

どうも、俺@仕事中です。

今日はオープンソースのロードバランサの1つの「Haproxy」について紹介します。
L7なのでアプリケーション層レベルでのロードバランシングが可能です。
※httpのURLパラメータを見てアクセスするサーバを振り分ける、など可能です。
※もちろんL4で稼働させることも可能です。

開発環境はCentOS5.6(64bit)です。

2013.10.21時点での安定版の最新はv1.4.24です。
上記のURLからtarballを落としてからインストールします。


tar zxvf haproxy-1.4.24.tar.gz
cd haproxy-1.4.24
make TARGET=linux26 ARCH=x86_64
sudo make install
# make時のフラグは同梱されているREADMEに書いているので、参考に!

これでデフォルトの/usr/local以下にインストールされます。
インストール先などのオプションを指定するには、同梱されているMakefileを変更すればOKです。

次に起動スクリプトを/etc/init.d以下へ

cp examples/haproxy.init /etc/init.d/haproxy
chmod +x /etc/init.d/haproxy
こうしておくことで
/sbin/service haproxy start
で起動したり出来ます。

つぎに設定ファイルです。

mkdir /etc/haproxy
cp examples/example.cfg /etc/haproxy/haproxy.cfg
すでにひな形があるので、それを元に設定できます。
設定については細かいオプションも用意されており、柔軟に設定可能です。

ちょっと長くなりそうなので、近いうちに"その2"書きます。

以上でぇぇぇぇぇえす。


※2013.11.07追記
L7ロードバランサHaproxyを使う(その2 設定から起動)書きました。


2013年9月20日金曜日

cocos2d-xでスクロールするレイヤーCCScrollLayerを使う

どうも、俺@久しぶりの書き込みです。

最近もほぼ毎日iOS/Androidのゲームアプリ開発に精を出しています。

今日はcocos2d-xを使ってスクロール出来るレイヤーの紹介です。
画面をスワイプしてページングする、アレです。
先日リリースしたゲームアプリ「ゴー!ゴー!カート」のコース選択画面で使っています。


GitHubに上がっているyandongliu / CCScrollLayerを使わせて頂きましたが、やりたい事がほぼこれで全て実装できました。
※cocos2d-x v2.0.2での動作保証がされています。それ以上のバージョンのcocos2d-xを使う場合はしっかり動作検証が必要です。

基本的な使い方は、スクロールして表示するコンテンツ(Layer)を配列にaddObject()しておいて、その配列をCCScrollLayerにセットする、という流れです。


ではまずGitHubからCCScrollLayerをcloneします。

git clone https://github.com/yadongliu/CCScrollLayer.git
で、中のCCScrollLayer.hとCCScrollLayer.mをXCodeのプロジェクト内に放り込みます。
これで準備OKです。

それでは表示する各コンテンツ(Layer)を作成しておきます。

// ヘッダ ContentsLayer.h
class ContentsLayer: public cocos2d::CCLayer
{
public:
  ContentsLayer();
  virtual bool init();
};

// 実装 ContentsLayer.m
#include "ContentsLayer.h"

ContentsLayer::ContentsLayer()
{
}
bool ContentsLayer::init()
{
  if (!CCLayer::init()) {
    return false;
  }

  // 適当なSpriteでも載せておく
  CCSprite *sprite = CCSprite::create("hoge.png");
  sprite->setPosition(ccp(200,200));
  this->addChild(sprite);

  return true;
}

次にスクロールさせたいSceneのヘッダファイルでこのファイルを読み込み宣言しておきます。

#include "CCScrolLayer.h"
#include "ContentsLayer.h"
class MyScene: public: cocos2d::CCLayer
{
public:
  MyScene();
  static cocos2d::CCScene *scene();
  // その他の宣言
private:
  // CCScrollLayerをクラス変数としておく(あとあと操作しやすいので、、各自お好みで、、)
  cocos2d::CCScrollLayer *_myScrollLayer;
};

次に実装ファイルに処理を書いていきます。


// コンストラクタやinit()で
bool MyScene::init()
{
  if (!CCLayer::init()) {
    return false;
  }

  // とりあえず4画面スクロールさせる
  CCArray *contentsList = CCArray::create();
  ContentsLayer *contents1 = new ContentsLayer();
  ContentsLayer *contents2 = new ContentsLayer();
  ContentsLayer *contents3 = new ContentsLayer();
  ContentsLayer *contents4 = new ContentsLayer();

  contents1->init();
  contents2->init();
  contents3->init();
  contents4->init();

  contentsList->addObject(contents1);
  contentsList->addObject(contents2);
  contentsList->addObject(contents3);
  contentsList->addObject(contents4);

  // CCScrollLayerへセット
  _myScrollLayer = new CCScrollLayer();

  // 4画面分の配列をセット。
  _myScrollLayer->initWithLayers(contentsList, 0);

  // ページインジケーターのポジション(任意)
  _myScrollLayer->setPageIndicatorPosition(ccp(100, 20));

  // 最初に表示しておくページ番号
  _myScrollLayer->selectPage(0);

  this->addChild(_myScrollLayer);

  // レイヤーは解放しておく
  contents1->release();
  contents2->release();
  contents3->release();
  contents4->release();

  return true;
}

とりあえずこれだけで動きます。 4画面分スクロールできるはずです。 他にも使えそうなメソッドがいくつか用意されていて、
CCArray *getPages() // 表示できる画面を配列で返す
unsigned int getCurrentScreen() // 現在のページ番号を返す

や、CCScrollLayerDelegateという便利なデリゲートもあります。

詳しくはソースを読んでみてください。
すごく短くて読みやすいです。


以上でぇぇぇぇぇす。

2013年8月28日水曜日

sftpで鍵認証する際のオプション

どうも、俺@仕事中です。

 いつも忘れるのでめもめも。 sftpコマンドを使ってサーバ接続する際に、公開鍵認証にしているときに鍵ファイルを指定する方法。
sftp -oIdentityFile=/path/to/鍵ファイル username@example.jp
オプションの -oIdentityFile= は username@example.jp の前に書かないとアカンで!


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

2013年8月22日木曜日

nginxにデフォルトの文字コードをセットしちゃる

どうも、俺@眠いです。

nginxでデフォルト文字コードをセット、というか自動でレスポンスヘッダに
Content-Type: text/html; charset=UTF-8
を追加させる方法についてメモメモ。

設定ファイル(/path/to/nginx.confなど)の
http, server, location
いづれかのディレクティブ内に
charset UTF-8;
を追加しちゃって
# service nginx reload
してやればOKです。

これを記述していない場合はデフォルトで
Content-Type: text/html;
だけがレスポンスヘッダに含まれます。


以上でぇぇぇぇぇぇす。

2013年7月23日火曜日

cocos2d-x Xcodeで"Symbol not found: ___CFObjCIsCollectable"というエラーが出る、でも大丈夫

どうも、俺@家です。

タイトルの件ですが、Xcodeでcocos2dxなアプリを開発しててiOSシュミレータで実行しようとすると、
Error loading /System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn:  dlopen(/System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn, 262): Symbol not found: ___CFObjCIsCollectable
  Referenced from: /System/Library/Frameworks/Security.framework/Versions/A/Security
  Expected in: /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
 in /System/Library/Frameworks/Security.framework/Versions/A/Security
のようなエラーメッセージが出まくる場合。
問題ない、大丈夫。no problem。
だってほら、シュミレータ実行できてるでしょ。
iOSシュミレータのバグだそうです。

Error: symbol not found: __CFObjCIsCollectable - stack overflow

以上でぇぇぇぇぇす。

2013年7月1日月曜日

tcpdumpじゃないtcpセッションツールmiruoが凄すぎた

どうも、俺@家です。 

最近、ネットワーク関連の調査でtcpについて調べたり、tcpdumpを使って通信のやり取りを見まくっていました。
 ネットワークについてボトルネックを調べるときは、Linuxサーバのカーネルの設定を見なおしたり、tcpdumpでtcpセッションの内容を確認したりします。
ググればたくさん出てきますが、ネットワーク関連については割と新しめのポストで
Linux Books Support Siteなどが参考になりした。

ところでtcpdumpですが、当然ながらとても便利です。
オプションも豊富で自分の知りたい情報を知ることができます。
ただし、大量アクセスのあるサイトで使うとあらゆるオプションを駆使してフィルタリングしても、ログが大量に出力されて解析が大変ですね。

「どこかの天才がもっとシンプルにTCPセッションを見れるツール作ってないかなぁ」と思っていたら、いました天才が。
高負荷サイトのボトルネックを見つけるには
しかも日本人、しかも2年も前。KLabの開発すげー。
miruoというツールです。

早速インストールしましょう。
※CentOS 6.2


git clone https://github.com/KLab/miruo.git
cd miruo
./configure
make
〜略〜
make[1]: *** [miruo.o] エラー 1
make[1]: ディレクトリ `/usr/local/src/miruo' から出ます
make: *** [all] エラー 2
ありゃ、エラーが出た。

makeのログをたどってみると、

miruo.h:24:17: error: pcap.h: そのようなファイルやディレクトリはありません
きっとpcapらしきライブラリが足りないみたい。


yum install libpcap-devel
よし、インストールを続けよう。


make
make install
make[1]: ディレクトリ `/usr/local/src/miruo' に入ります
test -z "/usr/local/sbin" || /bin/mkdir -p "/usr/local/sbin"
  /usr/bin/install -c miruo '/usr/local/sbin'
make[1]: `install-data-am' に対して行うべき事はありません.
make[1]: ディレクトリ `/usr/local/src/miruo' から出ます
これで/usr/local/sbin/miruoがインストール完了です!
〜に対して行うべき事はありません、と注意されますが、
心のなかで「そうなんですね」と返事しておきましょう。

このmiruoですが、「怪しいTCP通信」だけをピックアップして表示してくれるツールです。
なのでtcpdumpのように全TCPパケットを表示することもないので、解析がしやすくなります。
例えば
1392             0.343 |   (Client IP):50861 == (My Server IP):80    | Total 3 segments, 126 bytes
1392:0000 19:27:28.800 |          SYN_SENT >----S-> SYN_RECV          | 9098F675/00000000   78 - <mss=1410, wscale=4, timestamp 560465119 0, sackOK>
1392:0001 19:27:28.801 |       ESTABLISHED <-a--s- -="" 1392:0002="" 19:27:29.144="" 2e7570d5="" 66="" closed="" lt="" mss="1460," sackok="" syn_recv="" wscale="7>">---R--> CLOSED            | 9098F676/00000000   60 - <>

の場合だと、
1)クライアント→SYN→サーバ
2)サーバ→SYN+ACK→クライアント
3)クライアント→RST(強制終了)
のようなやり取りが行われていたり、

1431             0.345 |   (Client IP):48646 == (My Server IP):80    | Total 13 segments, 2185 bytes
1431:0000 19:27:28.824 |          SYN_SENT >----S-> SYN_RECV          | 6F591A36/00000000   74 - <mss=1420, sackOK, timestamp 14126836 0, wscale=5>
1431:0001 19:27:28.824 |       ESTABLISHED <-a--s- -="" 1431:0002="" 19:27:28.830="" 66="" b1fea867="" established="" lt="" mss="1460," sackok="" syn_recv="" wscale="7>">----S-> SYN_RECV          | 6F591A36/00000000   74 - <mss=1420, sackOK, timestamp 14126936 0, wscale=5>
1431:0003 19:27:28.830 |       ESTABLISHED <-a--s- -="" 1431:0004="" 19:27:28.903="" 66="" b1fea867="" established="" lt="" mss="1460," sackok="" syn_recv="" wscale="7>">-A----> ESTABLISHED       | 6F591A37/B1FEA868   60 - <>
1431:****              |                                              |
1431:0010 19:27:29.074 |         FIN_WAIT1 >-A---F> ESTABLISHED       | 6F591B62/B1FEACEE   60 - <>
1431:0011 19:27:29.074 |         FIN_WAIT2 <-a---f -="" 1431:0012="" 19:27:29.169="" 54="" b1feacee="" gt="" last_ack="" lt="" time_wait="">-A----> CLOSED            | 6F591B63/B1FEACEF   60 - <>
の場合は
1)クライアント→SYN→サーバ
2)サーバ→SYN+ACK→クライアント
3)クライアント→SYN (またSYNかよっ!
4)サーバ→SYN+ACK→クライアント (ほらよっ、二度目やで!
5)クライアント→ACK (やっと接続
のようなやり取りが行われていたり、一目瞭然です。



/usr/local/sbin/miruo --live
と打てば通常のtcpdumpコマンドと同等の結果を得ることも出来ます。
※ポートやホストの指定はできますが、tcpdump独自のオプション(-xや-v、-nなど)は使えませんので、
それらを使いたい場合はtcpdumpを使いましょう。

サーバ側のネットワーク関連のカーネルパラメータのチューニング不足や、クライアントからの不自然なパケット(または攻撃)などを捉える事が用意に出来ます。

SYN再送を補足するかどうか、RSTフラグのパケットを補足するかどうか、到達に◯ミリ秒以上かかった通信を補足するかどうか、などいくつか使えそうなオプションも用意されているので用途に合わせてオプション駆使することも可能です。
超便利。


以上でぇぇぇぇす。

2013年6月23日日曜日

tmuxのCtrl+b+tの使いどころ

どうも、俺です。
 以前の記事でscreenをやめてtmuxへを書いてから、 ずっとtmuxを使い続けています。

attachやらdetachやら便利ですし、ペイン分割や移動やコピー、ペーストも使いやすいし、色んなコマンドもあってとても便利です。


1つ使いどころが分からないコマンドがありました。

Ctrl + b + t
時間表示。



その時の時間が表示されるコマンドです。
「へー、そんなコマンドもあるんや」と意識せずにいたのですが、ある時このコマンドが必要な場面に遭遇しました。

それが、一番上の画像のようにペインを複数分割した際に、
「今、俺どのペインさわってんの!?」ってなる場合があります。

一応枠線が緑色になるんですが、ペインが多いと分かりずらい。。

そんな時は迷わず

Ctrl + b + t
で、時間を表示させます。
すると、あら不思議、自分が操作しているペインが一目でわかる。


でしょ。


以上でぇぇぇえっぇす。

2013年6月21日金曜日

c++で親クラスのコンストラクタを呼び出す

どうも、俺@家です。

C++でとある基底(親)クラスから派生した子クラスのコンストラクタ内で
親クラスのコンストラクタを呼び出したい場合は、

// 親クラス
class Parent
{
public:
  // 親クラスのコンストラクタ
  Parent()
  {
  };
};


// 子クラス
class Child: public Parent
{
public:
  // 子クラスのコンストラクタ
  Child(): Parent()
  {
  };
};
と書きます。
簡単ですね。

ちなみに子クラスから親クラスの何らかのメソッドを呼び出したい場合は、
// 親クラス
class Parent
{
public:
  // methodParent()の定義
  void methodParent()
  {
  };
};

// 子クラス
class Child: public Parent
{
public:
  void Child::methodChild()
  {
    // 親クラスのmethodParent()を呼びたい
    Parent::methodParent();
  };
};
のように、親クラス名::メソッド名と書きます。
※楽して上のように書きましたが、
 関数の重複定義でコンパイルエラーになる場合があるので、
 宣言する.hファイルと関数の内容を書く.cppファイルとは別けて書きましょう。


ちなみにphpだと
// 親クラス
public class Parent
{
  public function __construct()
  {
  }
}

// 子クラス
public class Child extends Parent
{
  public function __construct()
  {
    parent::__construct();
  }
}
のように、parent::メソッド()のように書きます。


ちなみにObjective-Cはコンストラクタがなくてイニシャライザになりますが、同様に
// 親クラスの.mファイル
@implementation Parent
- (id)init
{
  if ((self = [super init])) {
  }
  return self;
}
@end


// 子クラス .hファイル
@interface Child: Parent
- (id)init;
@end

// 子クラス .mファイル
@implementation Child
- (id)init
{
  if ((self = [super init])) {
  }
  return self;
}
@end
のようにsuperを使って書きます。
そもそもParentクラスも少なくともNSObjectを継承するのでsuperが出てきちゃいますね。


以上でぇぇぇぇえす。

2013年6月9日日曜日

apache付属のhtpasswdコマンドがなくてもBasic認証用ファイルを作る

どうも、俺@休みです。

Linuxサーバにnginx入れててBasic認証したいとき。

# vim /path/to/nginx.conf

-----------------------------
 78   location /secret {
 79       alias /home/foouser/secret_directory;
 80       autoindex on;
 81       auth_basic "member only";
 82       auth_basic_user_file /home/foouser/secrect_directory/.htpasswd;
 83   }
とかやると、
http://hoge.jp/secret以下にBasic認証がかかるようになります。
※.htpasswdファイルは外部から見れないようにする必要があります。

で、この.htpasswdファイルですが、apacheがインストールされている環境では
$ htpasswd -c /home/foouser/secret_directory.htpasswd username
で新規作成できますが、 「nginxしか入れてねぇし、apache入れるん面倒やで」という人は以下のコマンドでもOK。
echo "username:$(openssl passwd -crypt your_password)" >> /home/foouser/secret_directory.htpasswd
上記はcrypt暗号化ですが、他にも色々あるみたいです。
ココに答えが!


以上デェぇぇぇす。

2013年6月6日木曜日

cocos2d-xでiOSとAndroidのクロスプラットフォーム環境構築

どうも、俺@残業するフリしてブログ書き中です。


決して仕事をサボってるわけではありません。
今日はcocos2d-xを使ってiOSとAndroidの両方でアプリを動かす最初の環境構築をめもめも。
開発環境はMacOS X 10.8.3です。
Xcodeのインストールとeclipseのインストール、Androidアプリ開発環境は整備済みとします。


ちなみに、Cocos2d xをさらにさわってみよう!のスライドとがおまるさんのcocos2d-x環境構築〜Androidテンプレート起動までその1がとても参考になりますよ!

長いので手順を記しておきます。
1)cocos2d-xをDLしテンプレートインストール
2)Android側の準備
3)Xcode側でHelloWorld作成&起動
4)Android側でプロジェクト作成し、フォルダをXcode側へコピーしbuild_native.shの実行
5)eclipseへ取り込み、Android端末で起動
6)拍手
となります。


まず、お決まりのcocos2d-x本体をDLしましょう。
2013.06.06時点での安定版最新はv2.0.4でした。

解凍して適当なディレクトリへ置きましょう。
$ unzip cocos2d-2.0-x-2.0.4.zip

$ mkdir ~/Documents/cocos2dx

$ mv cocos2d-2.0-x-2.0.4 ~/Documents/cocos2dx/v2.0.4
# 以下は好みに合わせてね
$ ln -s ~/Documents/cocos2dx/v2.0.4 ~/Documents/cocos2dx/current
次にcocos2d-xのテンプレートをインストールしちゃいます。
$ sudo ~/Documents/cocos2dx/current/install-templates-xcode.sh
これでとりあえずXcodeでcocos2d-xのテンプレートを選択できるようになり、そのプロジェクトが作れます。
もちろんHelloWorldアプリも起動しますよ。
とりあえず拍手しましょう。

では、Android側の準備をしましょう。

AndroidNDKをDLして好きなディレクトリへ置きます。※すでにしてる人は要らない。
$ ls -l /Devloper

drwxr-xr-x@ 19 koexuka  staff   646 5 10 14:57 android-ndk-r8d
次にcreate-android-project.shを編集します。
このファイルはAndroidでcocos2d-xプロジェクトを新規作成するときに実行するファイルです。
$ vim ~/Documents/cocos2dx/current/create-android-project.sh
------------------------------------------------------
  7 # set environment paramters
  8 NDK_ROOT_LOCAL="/Developer/android-ndk-r8d"
  9 ANDROID_SDK_ROOT_LOCAL="/Developer/android-sdk-macosx" # Android-SDKの配置されているPATHに
次にtemplate/android以下にあるbuild_native.shを編集します。
$ vim ~/Documents/cocos2dx/current/template/android/build_native.sh
------------------------------------------------------
  1 APPNAME="__projectname__"
  2
  3 # 以下を追加
  4 NDK_ROOT=__ndkroot__
  5 COCOS2DX_ROOT=__cocos2dxroot__
  6 GAME_ROOT=$COCOS2DX_ROOT/__projectname__
  7 GAME_ANDROID_ROOT=$GAME_ROOT/proj.android
  8 RESOURCE_ROOT=$GAME_ROOT/Resources
  9

〜(中略)〜

 46 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 47 # ... use paths relative to current directory
 48 # 二重定義になっちゃうので以下をコメントアウト(COCOS2DX_ROOT)
 49 #COCOS2DX_ROOT="$DIR/../.."
 50 APP_ROOT="$DIR/.."
これを記述しておくと、Android用プロジェクトを作成するたびにbuild_native.shを編集する手間が減ります。

これでAndroid側の準備も完了。
ではHelloWorldアプリを作りましょう。

まずXcodeで、TestCocos2dxプロジェクトを作成しましょう。

プロジェクト名は「TestCocos2dx」にします。

で最後にCreateしちゃいましょう。

できたぜ、Hello World!


次はAndroidで動くようにします。

さっき編集したcreate-android-project.shを実行します。
$ ~/Documents/cocos2dx/current/create-android-project.sh

# 1)パッケージ名入力。
jp.blogspot.koexuka.app.test

# 2)AndroidターゲットIDの入力。なぜか僕はいつもid:2(android v2.2以上)を選択します。
2

# 3)最後にプロジェクト名。iOS側と合わせておいたほうが分かりやすいかも。
TestCocos2dx
そうすると配置したcocos2dxディレクトリ以下にプロジェクトディレクトリができます。
$ ls -l ~/Documents/cocos2dx/current
drwxr-xr-x   5 koexuka  staff    170  6  6 17:22 TestCocos2dx
できたプロジェクトディレクトリの中にproj.androidというディレクトリがあります。
$  ls -l ~/Documents/cocos2dx/current/TestCocos2dx

drwxr-xr-x   6 koexuka  staff  204  6  6 20:22 Classes
drwxr-xr-x   5 koexuka  staff  170  6  6 20:22 Resources
drwxr-xr-x  17 koexuka  staff  578  6  6 20:22 proj.android
これをXcodeのプロジェクトディレクトリ側へ持っていきます。

ここが分かりにくいですが、Finderを二つ並べてドラッグ&ドロップします。
別に問題ないとは思いますが、Xcode側のプロジェクトが無駄に大きくなってしまうので
proj.androidフォルダをXcode上へドロップしないようにしましょう。


もう1つ面倒な作業をします。
cocos2d-xのAndroid用javaプログラムファイルを、先ほどのXcode側のフォルダへ移します。
$ cp -R ~/Documents/cocos2dx/current/cocos2dx/platform/android/java/src/org/cocos2dx/lib ~/Documents/XcodeProject/TestCocos2dx/proj.android/src/org/cocos2dx
図解すると以下の様な感じ。


ここまで来れば90%出来たも同然!
ではAndroid用にビルドさせます。
$ cd ~/Documents/XcodeProject/TestCocos2dx/proj.android
$ ./build_native.sh
最初は時間がかかるので、しばらくジーッと画面を見つめておきます。

うまくいくと最後に
Compile++ thumb  : box2d_static <= b2World.cpp
Compile++ thumb  : box2d_static <= b2WorldCallbacks.cpp
Compile++ thumb  : box2d_static <= b2Rope.cpp
StaticLibrary  : libbox2d.a
SharedLibrary  : libgame.so
Install        : libgame.so => libs/armeabi/libgame.so
make: Leaving directory `/Users/koexuka/Documents/XcodeProject/TestCocos2dx/TestCocos2dx/proj.android'
のような表示になります。

もしここでコケる場合、build_native.shの内容を見なおす必要があります。
PATHの指定とか間違えてるかも!?

では出来たファイルをeclipseへ取り込むぜ。
eclipseを起動し、「File」→「New」→「Project...」と進み、

「Android」内にある「Android project from Existing Code」を選択しNext!

「Root Directory」は先ほどのXcodeプロジェクト内のproj.androidを選択します。

オッケー!!これでeclipseにプロジェクトが組み込まれたはず!


ではAndroid端末をPCへ接続しドキドキしながらRunボタンを押下仕様じゃないか!
ほら動いた!
あ、ちなみにcocos2d-xはAndroidエミュレータで起動できませんのであしからず。。。


開発手順ですが、基本的にはXcodeで開発します。
Android端末での動作を確認したい場合は、
1)build_native.shを実行
2)eclipse画面へ
3)eclipseのRunボタン押下
だけでOKです。
Resourceフォルダ以下へ画像や音声ファイルを追加しても、勝手にbuild_native.shが取り込んでlibgame.soを生成してくれるので
その辺は気にしなくてOKですよ!

あー、長かった!


※2013.06.20 Android.mkについて追記
とても大事な事を書き忘れていました(汗
上記のようにiOS/Androidでのクロスプラットフォーム向け開発環境を構築して開発開始してからですが、
上述したとおり基本的にはXcodeで開発をします。

Androidへの転送手順も上述のとおりなのですが、その際に「Android.mkの編集」という作業が必要になります。
このファイルは、新しくクラスファイルを追加した場合など、都度編集しなければいけません。
vim proj.android/jni/Android.mk
---------------------------------------
LOCAL_SRC_FILES := hellocpp/main.cpp ¥
  ../../Classes/AppDelegate.cpp ¥
  ../../Classes/HelloWorldScene.cpp ¥
  ../../Classes/MyClass.cpp ¥         # ←のように自作ファイル(.cppのみ)を追記
  ../../Classes/Utils/MyUtil.cpp ¥    # ←どんどん追記していく
〜(略)〜

もしBox2Dを使っている場合などは、
vim proj.android/jni/Android.mk
--------------------------------------
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes ¥
  $(LOCAL_PATH)/../../libs/cocos2dx/Box2D ¥    # ←とか
  $(LOCAL_PATH)/../../libx/cocos2dx/cocoa ¥    # ←必要だったこれとか
〜(略)〜
のように書いていく必要があります。

ちなみに未確認ですが、

Cocos2d-xで新しく作ったクラスを毎回Android.mkに追加せずに済ます

のようにして簡略化させることもできるそうです。

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


2013年6月4日火曜日

[C++] xcodeで "In-class initializer for static data member of type 'const float' is a GNU extension" というWarningが出る

どうも、俺@仕事中です。
ずっとcocos2d-x(c++)を使っての開発中です。

タイトルの件ですが、Xcodeでビルドしたときに
In-class initializer for static data member of type 'const float' is a GNU extension
というwarningが出て 「なんか気持ち悪いなぁ」となる人へ。

これは直訳すると、
「const floatというというstaticなメンバ変数の初期化をするのはGNU拡張だよ」という意味です。
簡単に言うと、
「const floatは普通は使えへんで、せやけどGNU拡張機能でコンパイルできるようになっとるんやで、感謝せえよアホ」
という意味です。

C++(C言語も?)では
const float
という宣言は仕様で禁止されているそうです。

このワーニングが出る場合、動作に問題はありませんが一応直し方を教えてくれている天才がいました。
にゃんにょんProgramTips

ヘッダファイル(HogeClass.h)
// 宣言
public:
  static const float HOGE_FLOAT;
としておき、
定義ファイル(HogeClass.cpp)
#include "hoge.h"
const float HogeClass::HOGE_FLOAT = 10.0f;

// 以下メソッドの定義等
すばらしい!

まぁ、
#define HOGE_FLOAT 10.0
とかでも良いんでしょうけどね。型が分かりにくいですしね。

以上でぇぇぇぇぇす。

2013年5月31日金曜日

iPhone/Androidゲームアプリ『ワイはスラッガー』リリースしました!

どうも、俺@仕事中です。

5/24(金)にcocos2d-xで開発したゲームアプリ『ワイはスラッガー』をリリースしました。
・iOS版はこちら
・Android版はこちら

使用したcocos2d-xのバージョンはv2.0.4です。




これまでcocos2d-iphonecocos2d-android-1を利用してきたのですんなりとcocos2d-xも利用できました。
よく出来てるね、cocos2d!

c++もだいたい問題なく入れました。
phpとかjavaとか経験ある人だと多分そんなに苦労することなくc++学習できると思います。
近いうちにcocos2d-xの記事書きます。

しかし、ゲーム開発は一般のwebシステム開発と違って、数字に強くある必要がありますね。。
物理的な計算とか時間的な計算とか、座標とか、、、結構苦労しました><

『ワイはスラッガー』是非一度DLして遊んでみて下さい!

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

2013年5月24日金曜日

dyld: Symbol not found: _OBJC_CLASS_$_NSJSONSerializationでハマった

どうも、俺@帰宅です。

iOSアプリ開発しててハマったのでφ(..)メモメモ

iOSv5.0以上だと問題なく動作するのに、
iOS4.3端末だとビルドは通りますが実行するとタイトルにもある
dyld: Symbol not found: _OBJC_CLASS_$_NSJSONSerialization
Expected in: /System/Library/Frameworks/Foundation.framework/Foundation
のエラーが出ちゃいました。

あ、先に解決方法から書いちゃいますが、
僕の場合はFacebook-SDKのv3.5.1を使っていた為、iOS4.xサポート外だったというオチです。。
チェンジログをちゃんと読め、ということですね。
なのでここから、iOSv4をサポートしているFacebook-SDKのv3.2.1を落としてきて対応しました。

で、本題の
dyld: Symbol not found: _OBJC_CLASS_$_NSJSONSerialization
ですが、これはそのまま
「NSJSONSerializationが見つからねぇよ!」というエラーです。
なぜiOSv4.3端末で見つからねぇかと言うと、NSJSONSerializatoinクラスはiOSv5以上で利用可能だからです。
参考:Apple開発者サイト

でも、deployment targetを4.3に指定してるとどうしてもiOSv4.3で動作させなければいけません。

もう一つ手がかりとなるのが、Xcode上に表示される
dyld`dyld_fatal_error:
0x2fe01080: trap 
0x2fe01084: mov r0, r0
のようなエラーです。
これはiOSv5.0以上に対応しているが、
それ未満には対応していないframeworkを呼び出したりしている場合に出やすいエラーです。
まさに今回の現象にズバリマッチしています。

そういう場合は読み込んだframeworkを "Optional" にするなどして対応出来るのですが、
今回の僕の場合はどのframeworkもOptionalに出来ませんでした。
で、組み込んだframeworkやSDKを1つずつチェックしてて、
Facebook-SDKのChangelogに気付いたという事でした。

もしFacebook-SDK(iOS)を利用してて同様のエラーに遭遇した人は確認してみてください。


以上でぇぇぇぇえす。

2013年4月13日土曜日

Node.jsのexportsとmodule.exportsについて

どうも、俺@休日中です。

最近少しだけ、プライベートでNodeをいじっています。
そういえば、初めてNodeを触ってからもう2年も経つんだなぁとシミジミ。
安定版なんかもうv0.10.3なんですね。

さて、過去のオデの日記で「node.jsで自作モジュールの作り方」というエントリーをポストしてますが、
この頃は多分あまりexportsとmodule.exportsの意味を理解していなかったようです。
※今もしていません。

今回それらを調べてみたところ、
exports
 関数をモジュール化する
module.exports
 オブジェクト(関数、配列、JSON、など)をモジュール化する
という認識で良いような気がしました。

あまり意味が分からない場合は、
Node.js Module – exports vs module.exports(※英語)にあるように、
標準は「module.exports」、補助的に「exports」という事なので、
特に深く考えずmodule.exportsを使うという認識でほぼ間違いはない気がします。

前回の僕のエントリーを元に考えます。
・exportsの場合
Person.js
exports.setName = function(name) {
  this.name = name;
};
exports.hello = function() {
  console.log("hello!");
};
exports.myName = function() {
  console.log(this.name);
};
app.js
var p = require("/path/to/Person");
p.setName("koexuka");
p.hello();  // "hello!"
p.myName();  // "koexuka"
これらはつまり、setName(name)、hello()、myName()という3つの関数を
var p = require("/path/to/person");
をp変数にオブジェクトとしてexportして使っています。
「意味的にPersonオブジェクトを生成して・・・」というより、上記3つの関数をまとめたオブジェクト、という感じでしょうか。

・module.exportsの場合]
Person.js
var Person = function(name) {
  this.name = name;
};
Person.prototype.hello = function() {
  console.log("hello");
};
Person.prototype.myName = function() {
  console.log(this.name);
};
module.exports = Person;
app.js
var Person = require("/path/to/Person");
var p = new Person("koexuka");
p.hello();  // "hello!"
p.myName();  // "koexuka"
こっちは、Personオブジェクトを取り出して使っています。

両方とも意味合いは同じですが、Person型のオブジェクトとして利用するという意味合いを持たせるには
module.exportsを利用するべきです。

ちなみにexportsとmodule.exportsが1つのファイル(例:Person.js)に混在している場合は
module.exportsが優先されてしまうので要注意。

以上でぇぇぇぇぇす。
もし間違いがあればご指摘下さいm(___)m

2013年4月8日月曜日

c++ 整数同士で割り算(除算)を行うと結果がゼロになっちゃう

どうも、俺@仕事中です。

C言語またはc++で整数同士の割り算を行った場合、
int a = 3;
int b = 5;
float z = a/b;
変数zの結果が0(ゼロ)になっちゃう!

こういう場合は

float z = (float)a/b;

のように、変数a(または変数b どちらでも)をfloat型またはdouble型でキャストしてやればOKです。
なぜなら、a/bはこの場合3/5 = 0...3 という結果になり、それがint同士で除算しているため
コンパイラに答えが0(ゼロ)と判断されてしまうからです。

以上でぇぇえぇっぇす。

2013年3月29日金曜日

CentOSにapache2.4.3をインストール

どうも、俺@寝る前です。

最近アプリ開発してばっかの俺が久しぶりにLinuxネタです。

2012/2月にapache2.4.1がリリースされて1年ちょっと経過し、
じわじわと情報が増えてきたところでようやく僕もapache2.4.3をインストールしてみました。
※2013/03/28時点での最新はv2.4.4

まずソースをDLして展開。
# wget 'http://ftp.meisei-u.ac.jp/mirror/apache/dist//httpd/httpd-2.4.3.tar.gz'
# tar zxvf httpd-2.4.3.tar.gz
# cd httpd-2.4.3
これまでだと、このまま./configureしてたのですが、2.4からはそれはNGです。
INSTALLファイルにこう書いています。
Consider if you want to use a previously installed APR and 
APR-Util (such as those provided with many OSes) or if you 
need to use the APR and APR-Util from the apr.apache.org
project. If the latter, download the latest versions and 
unpack them to ./srclib/apr and ./srclib/apr-util (no 
version numbers in the directory names) and use 
./configure's --with-included-apr option.
つまり--with-included-aprオプションを使うならaprとapr-utilをDL&展開して
./srclib以下にapr と apr-utilという名前で置きなさい。
ということらしい。
# cd ./srclib
# wget wget http://ftp.tsukuba.wide.ad.jp/software/apache//apr/apr-1.4.6.tar.gz
# wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache//apr/apr-util-1.5.1.tar.gz
# tar zxvf apr-1.4.6.tar.gz
# tar zxvf apr-util-1.5.1.tar.gz
# mv apr-1.4.6 apr
# mv apr-util-1.5.1 apr-util
あと途中でPCREも必要だと怒られたので入れておきます。
# wget 'ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.32.tar.gz'
# tar zxvf pcre-8.32
# ./configure --prefix=/usr/local/pcre/v8.32
# make
# make install
ではapacheのインストールを行います。
※オプションは適宜ご自由に。
# ./configure --prefix=/usr/local/apache2/v2.4.3 --with-included-apr --enable-module=so --enable-mods-shared=most --enable-ssl --enable-rewrite --with-mpm=prefork --with-pcre=/usr/local/pcre/v8.32
--with-mpm=preforkオプションを付けておかないと、デフォルトでevent-mpmでインストールされてしまいます。

非同期で多アクセスには強いですが、僕のようなPHPerな開発者にはprefork-mpmがオススメです。
# make
# make install
これで上手くインストールされるはずです。

後は基本的にこれまでのバージョンのものと同じですが、apacheの設定ファイルなんかは
order allow,deny
allow from all
だったものが、v2.4からは
Require all granted
# 禁止の場合は
# Require all denied
になります。
さらには、192.168.0.10のみ許可する場合は

  Require ip 192.168.0.10

となり、逆に192.168.0.10のみ拒否する場合は

  Require all granted
  Require not ip 192.168.0.10


# または

  Require all granted
  
    Require ip 192.168.0.10
  

のようになります。
うーん、なぜ今さら変えてくるかapache.org。
これまでの書き方は非推奨となるそうで、一応まだ使えるみたいです。

あと、MaxClientsはMaxRequestWorkersに書き変わりました。


以上でぇぇぇぇす。

2013年2月26日火曜日

UITableViewで「次を表示..」ページングを実装

どうも、俺@家です。

 今日はUITableView(UITableViewControllerでも同じだけど)を使ってデータを一覧表示させたときに、 「次を表示...」というセルを用意してページングを行う方法をφ(..)メモメモ

 UITableViewに表示させるデータ(dataSource)は、
NSMutableArray *datas
に保持しているものとします。
 まずページング用のセルを表示するための準備。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section                                 
{
  // データ件数
  int count = [datas count];

  // 初期
  if (count==0) {
    return 0;

  // _offsetCountは現在の画面に表示中のデータ件数
  // 「次を表示」を出すためにcount+1件だけセル数を返すようにする
  } else if (count==_offsetCount) {
    return count+1;
  }

  // 通常はデータ件数を返す
  return count;
}
これで、保持しているデータ+1件目に「次を表示」のセルを出す事ができます。
 次に実際にセルを作ります。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  // まずデータを持った通常のセル
  if (indexPath.row!=[datas count]) {
    // Cell再利用のためのIdentifier
    static NSString *CellIdentifier = @"NormalCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell==nil) {
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseidentifier:CellIdentifier] autorelease];
    }
    // 処理の必要があれば処理を書く
    return cell;

  // ページング用「次を表示」のセル(index.row==[datas count])
  } else {
    static NSString *CellIdentifier = @"NextCell";
    UITableViewCell *nextcell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (nextcell==nil) {
      nextcell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    nextcell.textLabel.text = @"次を表示";
    return nextcell;
  }
}
最後にタップされたときに次のデータを読み込ませます。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  // 選択状態解除
  [tableView deselectRowAtIndexPath:indexPath animated:YES];

  // 通常のセルが押された
  if (indexPath.row!=_offsetCount) {
    // ページ遷移などの処理
    XXViewController *viewController = [[XXViewController alloc] initWithNibName:nil bundle:nil];
    [self.navigationController pushViewController:viewController animated:YES];
    [viewController release];

  // 「次を表示」が押された
  } else {
    // 次を読み込ませるメソッド(サーバと通信するなど)
    [self loadNextData];

    // UITableViewを更新させる
    [tableView reloadData];
  }
}
これでざっとページングの完成です!
 よくある実装として、通常のセルと「次を表示」のセルとでサイズが異なる場合などは少しコツが必要なので、
 それはまた今度書きます。

 以上でぇぇえぇぇす。

2013年2月16日土曜日

UINavigationBarのナビゲーションバーに背景画像を設定する

どうも、俺@休み中です。
最近はずっとiOSアプリ開発に勤しんでいます。 

UINavigationBarを使って、ヘッダー部分(ナビゲーションバー)に画像を設定したい場合。 QiitaのUINavigationBarの背景画像を設定する方法を参考にさせてもらいました。
#import <QuartzCore/QuartzCore.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIViewController *viewController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];

    // OSのバージョン取得
    float osVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

    // iOS5未満
    if (osVersion < 5.0f) {
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"background.png"] stretchableImageWithLeftCapWidth:0 topCapHeight:1]];
        navBg.layer.zPosition = -FLT_MAX;
        [navigationController.navigationBar insertSubView:imageView atIndex:0];

    // iOS5以上
    } else if (osVersion >= 5.0f) {
        navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"background.png"] forBarMetrics:UIBarMetricsDefault];
    }
}
です。
 iOS5以上から
- (void)setBackgroundImage:(UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics

というメソッドが加わったため、iOS5未満の方法で同じように実装しても思ったように表示されません。

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

2013年1月21日月曜日

Objective-Cでファイルのタイムスタンプや属性を取得

どうも、俺@家です。
21日ですが、明けましておめでとうございます。
今年もよろしくお願いしマウス。チューチュー。

NSFileManagerでとあるディレクトリ以下にあるファイルを一覧で取得し、作成された日付順に並び替えたい場合。
// Cacheディレクトリ

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];


// ファイル一覧(サブディレクトリは除外)
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];


// 属性情報を格納する配列
NSMutableArray *attributes = [NSMutableArray array];


// ファイル配列をループ
for (NSString *file in files) {

  // ファイル属性にファイルパスを追加するためにDictionaryを用意しておく
  NSMutableDictionary *tmpDictionary = [NSMutableDictionary dictionary];

  NSString *filepath = [path stringByAppendingPathComponent:file];
   // ファイル情報(属性)を取得
   // 取得できる情報については csoulsの日記 を参考に!
  NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:nil];


  // tmp配列に属性を格納
  [tmpDictionary setDictionary:attr];

  // tmp配列にファイルパスを格納
  [tmpDictionary setObject:filepath forKey:@"FilePath"];

  [attributes addObject:tmpDictionary];
}


// ソートさせる
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:NSFileCreationDate ascending:NO];
NSArray *sortarray = [NSArray arrayWithObject:sortDescriptor];

// 並び替えられたファイル配列
NSArray *resultarray = [attributes sortedArrayUsingDescriptors:sortarray];

[sortDescriptor release];


なぜわざわざtmpDictionaryを用意するか?についてですが、
属性を取得する
  NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:nil];
は、NSDictionaryなためファイルパスが追加できないためです。


以上でぇぇぇえぇす。