query: tag:objective-c

at iPhoneOS 3.1.2

shouldAutorotateToInterfaceOrientationじゃなくて任意のタイミングで
roateする方法を探していたんだけど、見かけるのはUIViewのtransformでrotateすることばかり。確かめてないけど。この方法だとUIViewControllerのinterfaceOrientationと齟齬も発生するじゃないかと思う。

それで無理くり何とかする方法を考案した。けど、この方法では(もう少し改善すればできるかもしれないが)重力方向への回転しかできない。
shouldAutorotateToInterfaceOrientation:を使ってrotateすのはいつもとどおり。だけど先に方向を決めておいてNSNotificationを投げて強制的にshouldAutorotateToInterfaceOrientation:を発生させることによって
任意のタイミングでviewを回転させる事ができる。

objective-c>>

  • (void)rotateNow{
    UIDevice *device = [UIDevice currentDevice];
    self.toRotate = device.orientation;
    NSNotification *notification = [NSNotification notificationWithName:@"UIDeviceOrientationDidChangeNotification" object:device];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
    }

  • (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(self.toRotate){
    return interfaceOrient == self.toRotate;
    }else{
    return NO;
    }
    }
    <<--

こんな感じ。何をしたかったかと言うと向きが変わったときにいきなり回転させるんじゃなくて、ちょっとボタンをだして確認を取りたかった。だからタイミングだけずらして回転方向は重力方向だけでいいやって話しなんだけど。

もしかすると、このNSNotificationを作ってる部分でobject:deviceってUIDeviceを渡してる部分。このオブジェクトのプロパティorientationを任意の方向を返す様なオブジェクトを作ってViewControllerを更に騙すことができるならば、タイミングだけじゃなくて方向も変えれるんじゃないかな?そこまでは確認を取ってません。

まぁ何にせよ。かなりhackな方法だからOSのバージョン上がったら使えなくなるかもしれない。

posted by bopper bopper on Sun 31 Jan 2010 at 14:04 with 0 comments

Objective-CでMethodのIMPを取得して呼び出す場合に、
正しい関数プロトタイプの関数ポインタにキャストする必要がありますが、
typedefなどを使わずにその場で目的の関数ポインタ型にキャスト
する方法を紹介します。

objective-c>>
SEL selector = @selector(drawRect:);
Method method = class_getInstanceMethod([UISearchBar class], selector);
IMP drawRect = method_getImplementation(method);
((void(*)(id, SEL, CGRect))drawRect)(self, selector, rect);
<<--

こんな感じにすればOkです。

posted by genki genki on Thu 13 Nov 2008 at 01:12 with 0 comments

Xcodeでgdbを使ってObjective-Cのコードをデバッグしているときに、
Objective-Cのメソッドを呼んだ結果が知りたい場合、
以下のようにすれば良いようです。

objective-c>>
(gdb) call (int) [@"a" length]
$1 = 1
<<--

C関数の形式で以下のように呼び出してもOkです。

objective-c>>
(gdb) call (int) objc_msgSend(@"ab", @selector(length))
$2 = 2
<<--

ただし、戻り値のサイズや型によっては、objc_msgSend
ではなく、objc_msgSend_stretなどを使う必要があります。

posted by genki genki on Mon 13 Oct 2008 at 00:36 with 0 comments

Objective-Cで、Method構造体からCレベルの関数ポインタを取得する方法のメモです。

以前は、

objective-c>>
Method *method = class_getInstanceMethod(class, selector);
IMP imp = method->method_imp;
<<--

という感じで取得出来ていたみたいですが、現在はDeprecatedとなっており、
以下のようにする必要があるようです。

objective-c>>
IMP imp = method_getImplementation(method);
<<--

posted by genki genki on Thu 9 Oct 2008 at 02:25 with 0 comments

Objective-Cで、クラスやプロトコルを前方宣言(前方参照とも呼ばれたりします)をする方法のメモです。

クラスの前方宣言

クラスを前方宣言する場合は、@classに続いてクラス名、セミコロンを書きます。

objective-c>>
@class Foo;
<<--

プロトコルの前方宣言

クラスのときと同様、プロトコル名のあとにセミコロンでOk。

objective-c>>
@protocol Foo;
<<--

posted by genki genki on Wed 8 Oct 2008 at 16:52 with 0 comments

Objective-Cでオブジェクトを初期化する処理は、-init
メソッドなどの初期化メソッドで実装されます。
よく見かけるのはこんな例ですね。

objective-c>>

  • (id)init
    {
    [super init];
    /* initialization code */
    return self;
    }
    <<--

しかしながら、基底クラスの初期化処理[super init]の最中に、
メモリアロケーションの失敗などによって正常に初期化が行われなかった場合に備えて、次のようなエラーハンドリングを行った方が良いでしょう。

objective-c>>

  • (id)init
    {
    if(self = [super init]){
    /* initialization code */
    }
    return self;
    }
    <<--

この辺の処理はXcodeなどが生成するひな形にも書かれていますね。

さて、ここからが本題ですが、上述の
/* initialization code */
の中で初期化が失敗したときは、どうしたら良いでしょうか。
仕様的には、初期化に失敗したら nil を返す必要がありますが、
その際、途中までの段階で確保したリソースを解放する必要があるでしょう。
つまり、[super init]の中で確保されたであろうリソースを解放する必要があります。

objective-c>>

  • (id)init
    {
    if(self = [super init]){
    /* initialization code /
    if(/
    initialization failure /){
    /
    release all resources */
    [super dealloc];
    return nil;
    }
    }
    return self;
    }
    <<--

ということで、こんな感じに[super dealloc]
を呼び出して nil を返します。
ここで、[super release] を呼び出すと、
参照カウンタが0になり、 [self dealloc]
が呼び出されてしまうので注意が必要です。
[self dealloc]を呼び出すようにする場合は、上述の
/* release all resources */
の中でリソースを解放せずに、[self dealloc]
の中で解放するようにする必要があります。
しかし、失敗した初期化処理の中で中途半端に確保したリソースを、
正しく解放する為には、[self init]
の内部で解放処理まで行った方が楽な気がします。
あるいは、以下の様に初期化済みのものだけ解放するようなコードを
[self dealloc]に書いておくという手もあるかもしれません。

objective-c>>
#define RELEASE(x) if(x) [(x) release]

  • (void)dealloc
    {
    RELEASE(_something);
    [super dealloc];
    }
    <<--

こんなコードを見ると、なんだかノスタルジーを感じます。

ちなみに関係ないですが、このブログシステムでは、
Objective-Cのソースコードを以下のような記法でSyntax highlightさせる事ができます。

pre>>
objective-c>>
/* Objective-C code */
<<objective-c
<<pre

posted by genki genki on Mon 6 Oct 2008 at 22:09 with 4 comments