3

私は少し漬け物になっています。ブロック内から[selfmethodName]を呼び出すと、保持サイクルが発生することを知っています。

ただし、このクラスではマルチスレッドが原因で、ブロックがアクセスしているメソッドをブロック以外の場所から実行することを許可できません。重大な問題が発生する可能性があるためです。

現在のコード:

 if (_getRunning==NO){
        __weak SyncArrayMT *_weak_self = self;
        _get_t = ^void (void){
            _weak_self->_getRunning = YES;
            NSArray *objects = [_weak_self get:getQuery 
                                usingClassCtor:ctor 
                                 withAuthBlock:authBlock];
            if (_weak_self.getBlockCb)
                _weak_self.getBlockCb(objects);
            _weak_self->_getRunning = NO;
        };
    }

まさにそれを行い、[selfgetmethod]を呼び出します。ディスパッチされたブロックがこのメソッドを実行することは問題ありませんが、このクラスの外部でこのメソッドを呼び出すことは望ましくありません。したがって、この継承されたメソッドをそのままオーバーライドしても問題ありません。

- (NSArray *) get:(NSString *)getQuery usingClassCtor:(initBlock)initCb withAuthBlock:(authenticate)authBlock
{
    NSLog(@"Direct call to get is not allowed - use the threaded method");
    return nil;
}

次に、ブロックを次のように変更します。

        _get_t = ^void (void){
            _weak_self->_getRunning = YES;
            NSArray *objects = [super get:getQuery 
                                usingClassCtor:ctor 
                                 withAuthBlock:authBlock];
            if (_weak_self.getBlockCb)
                _weak_self.getBlockCb(objects);
            _weak_self->_getRunning = NO;
        };

私はそれを試しましたが、[self getMethod]を呼び出さなくても機能しますが、スーパーは保持され、適切に解放されますか?はい、ARCを使用しています。ブロック内でsuperを呼び出すと、問題が発生しますか?代わりに__weakをsuperにするためのハックはありますか?

または、[self getMethod](継承されます)への直接呼び出しを禁止し、内部でのみ使用するにはどうすればよいですか?Objective-Cがこれを正確に実装していないことは知っていますが、実装ファイルでのみメソッドを宣言して実装するなどのトリックがあることは知っています。

編集#1:

SEL&IMPと関数ポインタを試してみました。問題は、IMPおよび関数ポインターがパラメーターとしてインスタンスを必要とし、これによりホールポイントがミュートになることです。

NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,@selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);

これは単に継承されたメソッドを呼び出します。スーパーで使用しようとすると、エラーが発生します。この時点で、先に進み、ブロック内でsuperを使用し、プロファイルを作成して、保持サイクルにつながるかどうかを確認します。

編集#2:

newacctの回答に基づいて、これが私がやったことです。

typedef NSArray * (* getFuncPtr)(id,SEL,id,id,id);
...
...
__weak SyncArrayMT *_weak_self = self;
_getMethod = (NSArray * (*)(id,SEL,id,id,id))[[[self class] superclass] instanceMethodForSelector:@selector(get:usingClassCtor:withAuthBlock:)];
_get_t = ^void (void){
   NSArray *objects = _weak_self->_getMethod(_weak_self,@selector(get:usingClassCtor:withAuthBlock:),getQuery,ctor,authBlock);
}

実際にはまだプロファイルを作成していませんが、これによって保持サイクルが回避されることを期待しています。

4

1 に答える 1

5

ブロック内から[selfmethodName]を呼び出すと、保持サイクルが発生することを知っています。

それは一般的に真実ではありません。はい、ブロックは保持さselfれます。selfしかし、どういうわけかブロックを保持する場合にのみ「保持サイクル」があります。この場合はそうです。

しかし、スーパーは保持されます

はい、self保持されます(別のメソッドルックアップパスウェイでsuperの呼び出しです)。self

SEL&IMPと関数ポインタを試してみました。問題は、IMPおよび関数ポインターがパラメーターとしてインスタンスを必要とし、これによりホールポイントがミュートになることです。

NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)]; 
NSString *reply = getFuncPtr(_weak_self,@selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock); 

これは単に継承されたメソッドを呼び出します。スーパーで使用しようとすると、エラーが発生します。この時点で、先に進み、ブロック内でsuperを使用し、プロファイルを作成して、保持サイクルにつながるかどうかを確認します。

ここには多くの間違った点があります。まず、前述のように、superは呼び出しですself(オブジェクトなどはありませんsuper)。したがって、スーパークラスのメソッドのIMPを取得し、それを呼び出すだけで十分selfです。

しかし、スーパークラスのメソッドを取得[super methodForSelector:...しません。実際には、このクラスのメソッドを取得します。superinは、呼び出されるメソッドに[super methodForSelector:...影響します。methodForSelector:ただし、をオーバーライドするクラスはないmethodForSelector:ため、実際にはとの間に違いは[super methodForSelector:...ありません[self methodForSelector:...。上記のように、superのメソッドを呼び出すため、現在のオブジェクトselfのクラスに基づいてメソッドが検索されます。

クラスメソッドを使用すると、適切なIMPを取得できます+instanceMethodForSelector:

NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];

ただし、現在のオブジェクトがサブクラスのインスタンスである場合、上記の使用は正しく機能しません。これは、サブクラスに[self class]なるためです。したがって、希望どおりに動作することを確認するには、現在のクラスまたはスーパークラスの名前をハードコーディングする必要があります。

NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[SyncArrayMT superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,@selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);

直接使用することも可能ですobjc_msgSendSuperが、その機能もそれほど使いやすいものではありません。したがって、上記のIMPアプローチに固執する必要があると思います。

于 2013-01-03T03:30:56.897 に答える