12

Objective-C Blocks のカテゴリを作成して機能を追加したいと考えています。

__block int (^aBlock)(int) = ^int( int n ){
    if( n <= 1 ) return n;
    return aBlock( n - 1 ) + aBlock( n - 2 );
};

[aBlock copy]通常の , [aBlock retain], [aBlock release],を許可する代わりに[aBlock autorelease]。私は次のようなことができます:

[aBlock mapTo:anArray];

可能なカテゴリ

@interface UnknownBlockClass (map)

- (NSArray *)mapTo:(NSArray *)array_;

@end
4

5 に答える 5

13

見えないクラスのカテゴリを作成できないという点で、@pwc は正しいです。

でも...

私があなたに伝えようとしていることは、学習の練習として厳密に使用されるべきであり、いかなる種類の生産環境でも決して使用されるべきではありません.

  1. 実行時のイントロスペクションによって、いくつかの興味深い情報が明らかになります。「ブロック」という単語を含むクラスがいくつかあります。それらのいくつかは有望に見えます: __NSStackBlock__NSMallocBlock__NSAutoBlock、およびNSBlock.
  2. いくつかの内省は、有望なクラスがから継承していることを示していますNSBlock

したがって、どのブロックも のインスタンスまたはサブクラスになるように見えますNSBlock

次のように、オブジェクトにメソッドを作成できます。

@implementation Foo
- (void) doFoo {
  //do something awesome with self, a block
  //however, you can't do "self()".  
  //You'll have to cast it to a block-type variable and use that
}
@end

次に、実行時にそのメソッドをNSBlockクラスに移動できます。

Method m = class_getInstanceMethod([Foo class], @selector(doFoo));
IMP doFoo = method_getImplementation(m);
const char *type = method_getTypeEncoding(m);
Class nsblock = NSClassFromString(@"NSBlock");
class_addMethod(nsblock, @selector(doFoo), doFoo, type);

この後、ブロックはメッセージに応答する必要がありdoFooます。

自己責任で、実験目的でのみ使用してください。

于 2011-01-19T06:40:54.257 に答える
6

__NSGlobalBlock__次のスニペットに示すように、ブロックは type のインスタンスになります。

    ボイド (^aBlock)(ボイド) = ^(ボイド) {
        NSLog(@"Hello world");
    };

    // 出力 "type = __NSGlobalBlock__"
    NSLog(@"type = %@", [aBlock クラス]);

@interfaceクラスのカテゴリを作成するには、コンパイラがクラスの元の宣言を認識できる必要があります。__NSGlobalBlock__おそらく正当な理由での宣言が見つかりません。

この記事この記事には、ブロックの実装に関するいくつかの役立つ情報が含まれています。

NSArray元のポイントに、mapToメソッドのカテゴリを作成してみませんか? その種の機能にとっては、より良い場所のようです。

更新しました

ブロック オブジェクトにカテゴリを追加できるとします。カテゴリのメソッドからどのようにブロックを呼び出しますか? 私の理解では、ブロックを呼び出す唯一の方法は、()演算子 (例: aBlock()) を使用することです。Block オブジェクトからパラメーターの数と型を知る方法はないと思います。では、ブロック呼び出しにどの引数を渡しますか?

これを行うことはお勧めしませんが、次のように動作します...

@interface NSObject (ブロック拡張)
- (無効) フー;
@終わり

@implementation NSObject (BlockExtension)
- (ボイド)フー
{
    // 自分自身がブロックかどうかを判断する他の方法がわからない
    // __NSGlobalBlock__ もそのスーパークラスも (NSObject を除く)
    // コンパイラからアクセス可能
    if ([[[self クラス] 説明] isEqual:@"__NSGlobalBlock__"])
    {
        NSLog(@"foo");
        // それで?
        // self() を呼び出せず、コンパイルされません
        // 他にどのようにこのブロックを呼び出すことができますか?
    }
}
@終わり

...

ボイド (^aBlock)(ボイド) = ^(ボイド) {
    NSLog(@"Hello world");
};

// "foo" を出力します
[aBlock foo];
于 2011-01-19T05:52:45.370 に答える
1

Dave DeLong の言うとおりです。見えないクラスにカテゴリを追加することはできませんが、ブロックはNSBlock追加のサブクラスであるため、次のようになります。

@interface NSBlock : NSObject
@end

これで、カテゴリを「表示」NSBlockして追加できます。たとえば、次のようになります。

@interface NSBlock (map)
- (NSArray *)mapTo:(NSArray *)array;
@end

@implementation NSBlock (map)
- (NSArray *)mapTo:(NSArray *)array
{
    ...
}
@end

それでも、実際に本番環境で使用されるコードで行うのはおそらく最善ではありません...

于 2011-09-25T01:08:56.080 に答える
0
WRONG: A block winds up being an instance of type __NSGlobalBlock__, as seen in the     
following snippet:

int i = 0;
id o = [class self];

void (^aBlock)(void) = ^(void) {

    [o setValue:0];

    NSLog(@"Hello world %d", i);
};

// prints "type = __NSGlobalBlock__" 

// Now it prints __NSStackBlock__ 
// and when moved into HEAP prints __NSMallocBlock__

NSLog(@"type = %@", [aBlock class]);

スコープ内にキャプチャされた変数がない場合を除き、ブロックは「 NSGlobalBlock 」タイプのインスタンスになると言っても過言ではありません。すべての参照が保持されます。

于 2013-01-15T00:29:28.037 に答える
-2

簡単な答えはノーです。__block 変数は、Objective C オブジェクトではなく C レベル オブジェクトです。[aBlock copy] を呼び出すことはできますが、これは nsobject の copy メソッドではなく、C 関数 block_copy() を呼び出します。__block 型は C 型なので、カテゴリを追加することはできません。

修正: __block は、typedef ではなく C コンパイラの識別子です。

これがあなたが思っていることを達成するかどうかはわかりませんが、実際には、それが何をするのかよくわかりません:

__block int (^aBlock)(int) = ^int( int n ){
if( n <= 1 ) return n;
return fib( n - 1 ) + fib( n - 2 );
};

__block 識別子は、変数が参照ブロックで変更可能であり、参照ブロックがヒープにコピーされた場合に保持される必要があることをコンパイラに伝えます。あなたのコードについて私を混乱させるのは、ブロック自体ではなく、変数をラップするために __block が通常使用されることです。

于 2011-01-19T05:29:53.223 に答える