コンピュータやソフトウェアのあれこれ@道民(&元道民)
Cocoa
[iPhone][Cocoa]self retain した話
5月 17th
こんなコードでハマりまして、
#import <Foundation/Foundation.h> @class MainClass; @interface WorkerClass : NSObject -(void)run:(MainClass *)target; @end @interface MainClass : NSObject @property(retain, nonatomic) WorkerClass *worker; -(void)run; -(void)done; @end @implementation WorkerClass -(void)cleanUp { // Do cleanup ... } -(void)run:(MainClass *)target { /* ... Do some tasks */ ... [target done]; [self cleanUp]; // ←ここではselfが解放されているのでセグフォる } @end @implementation MainClass @synthesize worker; -(void)run { WorkerClass *newWorker = [[WorkerClass alloc] init]; self.worker = newWorker; [newWorker release]; [worker run:self]; } -(void)done { self.worker = nil; } -(void)dealloc { self.worker = nil; [super dealloc]; } @end int main () { MainClass *main = [[MainClass alloc] init]; [main run]; [main release]; }
Appleのドキュメントの似たような例を読むと retain + autorelease しろって話が書いてあって、[self retain]をググってみたら何件か例があったので、
-(void)run:(MainClass *)target { /* ... Do some tasks */ ... [self retain]; [target done]; [self cleanUp]; [self release]; }
としたって話。これを一般的な話にしちゃうと「delegateへメッセージを送る前にはself retain」ってことになりそうなもんだけど、もっといい解決法はありますかねー。
delegate にメッセージ送信したら即return すれば問題ないので、cleanup の呼び出しをdeallocに任せるってのはありかなとは思いました。
5/19 追記
performSelector:withObject:afterDelay:の類いはThis method retains the receiver and the arg parameter until after the selector is performed.なんだから、selfと引数はretainされてると嬉しいなあと思ったり。パフォーマンス面の問題なんだろうけど。
[iPhone][Cocoa]self retain しなくてよかった話
5月 17th
こんなコードでハマりまして、
#import <Foundation/Foundation.h> @class MainClass; @interface WorkerClass : NSObject -(void)run:(MainClass *)target; @end @interface MainClass : NSObject @property(retain, nonatomic) WorkerClass *worker; -(void)run; -(void)done; @end @implementation WorkerClass -(void)cleanUp { // Do cleanup ... } -(void)run:(MainClass *)target { /* ... Do some tasks */ ... [target done]; [self cleanUp]; // ←ここではselfが解放されているのでセグフォる } @end @implementation MainClass @synthesize worker; -(void)run { WorkerClass *newWorker = [[WorkerClass alloc] init]; self.worker = newWorker; [newWorker release]; [worker run:self]; } -(void)done { self.worker = nil; } -(void)dealloc { self.worker = nil; [super dealloc]; } @end int main () { MainClass *main = [[MainClass alloc] init]; [main run]; [main release]; }
Appleのドキュメントの似たような例を読むと retain + autorelease しろって話が書いてあって、[self retain]をググってみたら何件か例があったので、
-(void)run:(MainClass *)target { /* ... Do some tasks */ ... [self retain]; [target done]; [self cleanUp]; [self release]; }
としたって話。これを一般的な話にしちゃうと「delegateへメッセージを送る前にはself retain」ってことになりそうなもんだけど、もっといい解決法はありますかねー。
delegate にメッセージ送信したら即return すれば問題ないので、cleanup の呼び出しをdeallocに任せるってのはありかなとは思いました。
5/19 追記と修正
考え直したので追記。performSelector:withObject:afterDelay:の類いはThis method retains the receiver and the arg parameter until after the selector is performed.となってますが、これらと同様に呼び出し側が実行終了までレシーバと引数の所有権を持つのがよいプラクティスでしょう。そう考えると、単にWorkerClass#run の呼び出し側が
WorkerClass *existsWorker = [[self.worker retain] autorelease];
[existsWorker run:self];
等とすべき。こうすると先に書いたAppleのドキュメントと同じになりますね。
[Cocoa][iPhone]XcodeのビルドのRun Scriptではシグナルがブロックされているぽい
4月 26th
XcodeのBuild Phasesの設定でRun Script を追加できますが、例えば以下のようなスクリプトを設定してビルド中に実行すると、kill -TERM を送っても止められなくなります。
#!/bin/sh perl -e 'sleep 3600'
普段は困らないのですが、例えばTest::TCP のように子プロセスにTERMを送って処理を終了させるようなコードを動かす場合には困ってしまいます。
で実際に困ったわけで、@havanaclub_さんにアドバイスをもらったりしつつ見つけた解決法が以下。ただし、*nixのプロセスやシグナル周りはよくわかってないので、これが正しい解決法なのかはわかりません。
#!/usr/bin/perl use POSIX (); defined POSIX::sigprocmask( POSIX::SIG_UNBLOCK, POSIX::SigSet->new(POSIX::SIGTERM), undef ) or die;
これを、TERMを受け取りたいプロセス内でやっておけばOKです。Test::TCPであれば、serverブロック側。
ちなむと、実際にブロックされてるシグナルは以下です。
#!/usr/bin/perl use POSIX (); my $old_set = POSIX::SigSet->new(POSIX::SIGTERM); defined POSIX::sigprocmask(POSIX::SIG_SETMASK, undef, $old_set) or die; for (qw/ SIGABRT SIGALRM SIGCHLD SIGCONT SIGFPE SIGHUP SIGILL SIGINT SIGKILL SIGPIPE SIGQUIT SIGSEGV SIGSTOP SIGTERM SIGTSTP SIGTTIN SIGTTOU SIGUSR1 SIGUSR2 /) { no strict 'refs'; my $sig = &{"POSIX::$_"}; $old_set->ismember($sig) and warn "$_ is blocked.\n"; } __END__ 【結果】 SIGALRM is blocked. SIGCONT is blocked. SIGHUP is blocked. SIGINT is blocked. SIGQUIT is blocked. SIGTERM is blocked. SIGTSTP is blocked. SIGTTIN is blocked. SIGTTOU is blocked. SIGUSR1 is blocked. SIGUSR2 is blocked.
止められる物は全部止めてる感じでしょうか? ビルド中に割り込まれると何が起こるかわからんからってことだと思います、タブン。