我有点腌渍。我知道从块中调用[self methodName]会导致保留周期。
但是在这个类中由于多线程,我不能允许执行块从块以外的任何其他地方访问的方法,因为它可能会导致严重的问题。
当前代码:
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;
};
}
确实如此,它称之为[self getmethod]。虽然调度块可以运行此方法,但我不希望此类之外的任何内容调用此方法。 那么,可以这样覆盖这个继承的方法:
- (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。在一个街区内召唤超级会导致任何问题吗?是否有一个hack来获得__weak而不是超级?
或者,如何禁止直接调用[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);
}
我希望这应该避免任何保留周期,虽然我还没有实际描述它。
答案 0 :(得分:5)
我知道从一个块中调用[self methodName]会导致 保留周期。
总的来说,情况并非如此。该块将保留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:...
不获取超类中的方法。它实际上是在 this 类中获取方法。 super
中的[super methodForSelector:...
会影响调用哪个methodForSelector:
方法。但是,任何课程都不会覆盖methodForSelector:
,因此[super methodForSelector:...
和[self methodForSelector:...
之间实际上没有任何区别。如上所述,super
会在self
上调用该方法,因此它仍会根据当前对象的类找到该方法。
您可以使用类方法+instanceMethodForSelector:
获得正确的IMP:
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方法。