メモ。
■iOS
[textField setPlaceholder:@"(^o^)"];
■android
editText.setHint("(^o^)");
メモ。
[textField setPlaceholder:@"(^o^)"];
editText.setHint("(^o^)");
btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [btn setTag:BTN]; [btn setFrame:CGRectMake(200, 5, 50, 50)]; [btn setTitle:@"t" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(onCellButtonPushed:event:) forControlEvents:UIControlEventTouchUpInside]; [cell.contentView addSubview:btn];
以下のようにしてどのcellのボタンが押されたか判定する。
- (void)onCellButtonPushed:(UIButton *)button event:(id)event { NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition]; if (indexPath != nil) { } }
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
まず、コミットのハッシュ値を調べる
gitx
gitxを入れていない場合は以下のコマンドで調べる。
git log --all --graph
以下のコマンドで一度チェックアウトしたあとブランチを切った後、元のブランチをチェックアウトする。
git checkout 1234567 git branch -a git checkout -b forgetbranch git checkout master
addしてないファイルとかあると少し面倒になる。
サービスには2種類の起動方法がある。
package info.justoneplanet.android.sample.service; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.widget.Toast; public class ServiceActivity extends Activity { private Intent mIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ブロードキャストレシーバの設定(サービスには直接関係しない) IntentFilter filter = new IntentFilter(SampleService.ACTION); registerReceiver(new ServiceReceiver(), filter); } @Override public void onResume() { super.onResume(); // サービスの起動 mIntent = new Intent(this, SampleService.class); startService(mIntent); } @Override public void onPause() { super.onPause(); // サービスの停止 stopService(mIntent); } /** * テスト用のブロードキャストレシーバ<br> * 実行されるとToastを表示する * @author justoneplanet */ private class ServiceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getApplicationContext(), "hello", 200).show(); } } }
package info.justoneplanet.android.sample.service; import java.util.Timer; import java.util.TimerTask; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; public class SampleService extends Service { public static final String ACTION = "SampleService.ACTION"; private Timer mTimer; /** * サービスが一番初めに作られたときに実行される */ @Override public void onCreate() { super.onCreate(); mTimer = new Timer(); Toast.makeText(getApplicationContext(), "onCreate", 1000).show(); } /** * サービスがスタートするごとに実行される<br> * 但しこのメソッドは2.0以降は非推奨でonStartCommandを使うことが推奨されている */ @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); hello(); Toast.makeText(getApplicationContext(), "onStart", 1000).show(); } /** * サービスが無効になり取り除かれるときに実行される */ @Override public void onDestroy() { super.onDestroy(); mTimer.cancel(); Toast.makeText(getApplicationContext(), "onDestroy", 1000).show(); } /** * クライアントで登録したBroadcastReceiverに対してIntentを送る */ public void hello() { mTimer.schedule( new TimerTask() { @Override public void run() { sendBroadcast(new Intent(ACTION)); } }, 200, 2000 ); } @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "onBind", 1000).show(); return null; } }
stopServiceを呼ばずにアプリを終了した場合は、バックグラウンドで動き続ける。
package info.justoneplanet.android.sample.service; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.widget.Toast; public class ServiceActivity extends Activity { private Intent mIntent; private SampleService mSampleService; /** * サービスをモニタリングするインターフェース<br> * 状態に応じて各メソッドがinvokeされる */ private ServiceConnection conn = new ServiceConnection() { /** * サービスとの切断時に呼ばれる */ @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(getApplicationContext(), "onServiceDisconnected", 1000).show(); } /** * サービスとの接続時に呼ばれる */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(getApplicationContext(), "onServiceConnected", 1000).show(); mSampleService = ((SampleService.LocalBinder)service).getService(); mSampleService.hello(); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ブロードキャストレシーバの設定(サービスには直接関係しない) IntentFilter filter = new IntentFilter(SampleService.ACTION); registerReceiver(new ServiceReceiver(), filter); } @Override public void onResume() { super.onResume(); // サービスの起動 mIntent = new Intent(this, SampleService.class); bindService(mIntent, conn, Context.BIND_AUTO_CREATE); } @Override public void onPause() { super.onPause(); // サービスの停止 unbindService(conn); } /** * テスト用のブロードキャストレシーバ<br> * 実行されるとToastを表示する * @author justoneplanet */ private class ServiceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getApplicationContext(), "hello", 200).show(); } } }
package info.justoneplanet.android.sample.service; import java.util.Timer; import java.util.TimerTask; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.widget.Toast; public class SampleService extends Service { public static final String ACTION = "SampleService.ACTION"; private Timer mTimer = new Timer(); /** * ActivityでサービスのインターフェースにアクセスするためのBinder * @author justoneplanet */ public class LocalBinder extends Binder { public SampleService getService() { return SampleService.this; } } private IBinder mIBinder = new LocalBinder(); /** * バインドされた時に実行される */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "onBind", 1000).show(); return mIBinder; } /** * バインドが解除されtrueを返した後、再度バインドすると実行される */ @Override public void onRebind(Intent intent) { Toast.makeText(getApplicationContext(), "onRebind", 1000).show(); } /** * バインドが解除されたときに実行される */ @Override public boolean onUnbind(Intent intent) { Toast.makeText(getApplicationContext(), "onUnbind", 1000).show(); mTimer.cancel(); return true; } /** * クライアントで登録したBroadcastReceiverに対してIntentを送る */ public void hello() { mTimer.schedule( new TimerTask() { @Override public void run() { sendBroadcast(new Intent(ACTION)); } }, 200, 2000 ); } }
Thread thread = new Thread();
以下のようにすることで互いに別スレッドで動作するプログラムを記述できる。
class PingPong extends Thread { private String mWord; private int mDelay; public PingPong(String word, int delay) { mWord = word; mDelay = delay; } @Override public void run() { try { for(;;) { System.out.println(mWord); Thread.sleep(delay);// 自身が実行されているスレッドで次の時間まで待つ } } catch(InterruptException e) { return;// スレッドを終了させる } } // スタートする public static void main(String[] args) { new PingPong("ping", 33).start(); new PingPong("PONG", 99).start(); } }
但し、以下のようにRunnableを使った記述のほうが一般的ではある。
Runnableインタフェースを実装しThreadにセットすることができる。
class RunPingPong extends Runnable { private String mWord; private int mDelay; public PingPong(String word, int delay) { mWord = word; mDelay = delay; } @Override public void run() { try { for(;;) { System.out.println(mWord); Thread.sleep(delay);// 自身が実行されているスレッドで次の時間まで待つ } } catch(InterruptException e) { return;// スレッドを終了させる } } // スタートする public static void main(String[] args) { Runnable ping = new RunPingPong("ping", 33); Runnable ping = new RunPingPong("PONG", 99); new Thread(ping).start(); new Thread(pong).start(); } }
コンストラクタでスレッドを開始させるとコンストラクタが実行される前にスレッドがオブジェクトのフィールドにアクセスできてしまうため危険である。
class PrintServer implement Runnable { private final PrintQueue q = new PrintQueue(); public PrintServer() { Runnable service = new Runnable() { } new Thread(this).start(); } @Override public void run() { for(;;) { realPrint(); } } public void print(Print job) { q.add(job); } public void realPrint(Print job) { // 実際の処理 } }
一般的には以下のように使用される。
class PrintServer { private final PrintQueue q = new PrintQueue(); public PrintServer() { Runnable service = new Runnable() { @Override public void run() { for(;;) { realPrint(); } } } new Thread(service).start(); } public void print(Print job) { q.add(job); } public void realPrint(Print job) { // 実際の処理 } }
スレッドは生成された時に自身への参照を自身のThreadGroupに保持する。
全てのオブジェクトはロックを持っている。そのロックはsynchronizedメソッドやsynchronized文を使用することにより獲得したり解放したりできる。
以下の例では、synchronizedされたアクセサによって残高が同期なしに修正できないように保護されている。
public class BankAccount { private long number; private long balance;// 残高 public BankAccount(long initialDeposit) { balance = initialDeposit; } public synchronized long getBalance() { return balance; } public synchronized long deposit(long amount) { balance += amount; } }
フィールドが外部から直接アクセス可能であった場合は同期を取る必要がない。
オブジェクトが生成される時だけ実行され新たなオブジェクトを生成する際には1つのスレッド内だけで実行される。
staticなフィールドのデータがスレッド間で共有されている場合、staticでsynchronizedされたメソッドからアクセスする必要がある。この時、自身に関連付けられたClassオブジェクトに対してロックがかかるが、synchronizedされたメソッドに対してのinvokeのみブロックの対象となる。
以下のようにすることで現在のスレッドがオブジェクトに対してロックを保持しているか判定できる。
Thread.holdLock(this);
以下のようにすることでカレントオブジェクトではなく任意のオブジェクトに対してのロックを獲得できる。但し、exprはオブジェクトの参照を返す必要がある。
synchronized(expr) { statements }
synchronizedメソッドはthisへの参照を伴うsynchronized文であり省略した表現である。
public static void abs(int[] values) { synchronized(values) { for(int i = 0; i < values.length; i++) { if(values[i] < 0){ values[i] = -values[i]; } } } }
エンクロージングオブジェクトに対して内部オブジェクトが同期を取る。
public class Outer { private int data; public class Inner { void setOuterData() { synchronized(Outer.this) { data = 1; } } } }
コンストラクタ内で使用される。
class Body { Body() { synchronized(Body.class) { idNum = nextID++; } } }
クラスに対して適切な同期を設計することは複雑で難しい。
class Util { private int value; Util(int initial) { value = initial; } public synchronized add(int x) { value += x; System.out.println("value:" + value); } } // Util util = new Util(5); // thread a : util.add(7); // thread b : util.add(9); // 5 12 21 // 5 14 21
class Util { private static int value = 0; public synchronized static add(int x) { value += x; System.out.println("value:" + value); } } // thread a : Util.add(7); // thread b : Util.add(9); // 0 7 16 // 0 9 16
class Util { private static int value = 0; public synchronized static add(int x) { value += x; System.out.println("value:" + value); } public static subtract(int x) { add(-x); } }
条件を待つスレッドは以下のように記述する。
synchronized void doWhenCondition() { while(!condition) {// whileをifにしてはいけない wait(); } // 処理 }
スレッドを(一時)停止させるときにwaitはオブジェクトのロックをアトミックに解放する。(スレッドを停止した場合にロックの解放までがアトミックである)
以下のようにして他のスレッドに通知する。
synchronized void changeCondition() { // 条件で使用される値の変更処理 notifyAll();// notify(); }
notifyAllを使用するのは以下の条件のときである。
notifyAllを使うことによって(superクラスの)notifyが機能しなくなる可能性がある。
class PrintQueue { private SingleLinkQueue<PrintJob> queue = new SingleLinkQueue<PrintJob>(); /** * プリントキューの追加<br> * 他の待っているスレッドに通知する */ public synchronized void add(PrintJob job) { queue.add(job); notifyAll(); } /** * 他のスレッドが何か挿入するまで待つ */ public synchronized PrintJob remove() throws InterruptedException { while(queue.size() == 0) { wait();// プリントジョブが追加されるのを待つ } return queue.remove(); } }
currentスレッドは以下の4つのケースまで待つ。
タイムアウトか条件を満たしたか知る必要がある場合は経過時間を計測する必要がある。
ロックが保持されていない時に使用するとIllegalMonitorStateExceptionが投げられる。
実行しているスレッドは以下の条件のどれかまで実行を続ける。
UIスレッドはNORM_PRIORITY+1で実行され、他のスレッドはNORM_PRIORITY-1で実行されることが多い。
ランタイムはデッドロックを検出したり防いだりはしないので、設計でデッドロックの可能性を熟考する必要がある。
ロックを獲得するオブジェクトに関して常に同じ順序でロックを取得するようにする。
以下の条件の時にスレッドは終了する。
キャンセルは割り込みによって実現される。
thread2.interrupt();
thread2では以下のような処理が記述されているとする。
void tick(int count, long pauseTime) { try { for(int i = 0; i < count; i++) { System.out.println(','); System.out.flush(); Thread.sleep(PauseTime); } } catch(InterruptedException e) {// 他のスレッドから割り込みされた時 Thread.currentThread().interrupt(); } }
下述の2点に注意して強調しているコードがマルチスレッドを生かして処理できるようにする必要がある。
class CalcThread extends Thread { private double result; @Override publc void run() { result = calculate(); } publc double getResult() { return result; } publc double calculate() { // calc } }
class ShowJoin { public static void main(String args[]) { CalcThread calc = new CalcThread(); calc.start(); doSomethingElse(); try { calc.join();// joinが戻ってきたときにはrunが終了されていることが保証される System.out.println("result is " + calc.getResult()); } catch(InterruptedException e) { System.out.println("No answer: interrupted"); } } }
最後のユーザスレッドが終了するとデーモンスレッドは消滅させられてアプリケーションは終了する。
同期順序は常にプログラム順序と整合性が取れる。単一のスレッドが更新し多数のスレッドから読み取る場合は同期の必要がないが、多数のスレッドが更新した値にアクセスするような場合は同期が必要でvolatile修飾子を検討する。
以下のコマンドでファイルを編集する。
vi /etc/rc.d/rc.local
以下のような記述があると思う。
touch /var/lock/subsys/local
最終行に起動時に実行したいコマンドを記述する。
ulimit -n 32768 /home/hogehoge/fugafuga/check.sh > /home/hogehoge/fugafuga/result.txt &
そーいやmacで使ってなかったので一応メモ。
cd ~/.ssh ssh-keygen -t rsa -C "user@hogehoge.com" Generating public/private rsa key pair. Enter file in which to save the key (/var/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /var/root/.ssh/id_rsa. Your public key has been saved in /var/root/.ssh/id_rsa.pub.
以下のコマンドで内容をメモる。
vi id_rsa.pub
Account Settingsのキーの方にペーストする。
ssh -T git@github.com Hi hogehoge! You've successfully authenticated, but GitHub does not provide shell access.
以下のコマンドでapacheを再起動する。
/etc/init.d/httpd restart
以下のようなメッセージが表示されて再起動できなくなる。
Starting httpd: (98)Address already in use: make_sock: could not bind to address [::]:80
以下のコマンドでポートを使用しているプロセスを調べる。
/usr/sbin/lsof -i | grep http
プロセス番号が表示されるのでkillする。
バッチ処理したい時などに使う技である。
以下のようにしてShellクラスを継承する。基本的にはコントローラと同様にモデルなどが使用できるがコンポーネントについては注意が必要である。
date_default_timezone_set('Asia/Tokyo'); //Configure::write('Config.environment', isset($_SERVER['CAKE_ENV']) ? $_SERVER['CAKE_ENV'] : "development");// コマンドラインから叩いている場合、$_SERVERによる環境分岐ができない Configure::write('Config.environment', "production"); class RankShell extends Shell { public $uses = array( 'Logs', 'Ranks' ); /** * 処理を実行する前に読み込むコンポーネントなどを記述する */ public function initialize() { parent::initialize(); //$this->Email = new EmailComponent($this);// コンポーネント名に注意 } /** * ここに記述した処理が実行される */ public function main() { $this->out("start"); if($result = $this->Log->getRank()){ $this->Ranks->deleteAll(); if($this->Ranks->saveAll($result)){ $this->out("success"); } else{ $this->out("failed to save"); } } else{ $this->out("failed to calc"); } } }
以下のようにして実行できるかどうか確認する。
/usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
以下のコマンドを実行してcrontabを編集する。
crontab -e
例えば10時のオヤツを忘れないよう10:15に実行するようにするには以下のようにする。
15 10 * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
15分ごとに処理をするには以下のように記述する。
*/15 * * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
以上のようにCakePHPでは非常に簡単にバッチ処理を書くことができる。個人的にはZendFrameworkよりも簡単に感じる。