I'm in a bit of a pickle. I know that calling [self methodName] from within a block will lead to a retain cycle.
我有点麻烦。我知道从一个块中调用[self methodName]将会导致一个retain cycle。
However in this class due to multithreading I cannot allow execution of the method that the block is accessing from anywhere else other than the block, as it would potentially lead to serious problems.
但是在这个类中,由于多线程,我不能允许执行块从其他任何地方访问的方法,因为它可能会导致严重的问题。
Current code:
当前代码:
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;
};
}
Does exactly that, it calls [self getmethod]. While its ok for the dispatched block to run this method, I do not want anything outside this class calling this method. So, would it be ok to override this inherited method as such:
它会调用[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;
}
And then change the block to this:
然后把block改成:
_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;
};
I have tried it and it works without doing a call to the [self getMethod], but will super be retained, properly released, etc? Yes I am using ARC. Would calling super within a block lead to any problem ? Is there a hack to get a __weak to super instead ?
我已经尝试过了,它可以在不调用[self getMethod]的情况下工作,但是super会被保留、被适当释放等等吗?是的,我在用弧线。在一个块中调用super会导致任何问题吗?有没有办法让弱队变成超级?
Alternatively, how can I disallow direct calls to [self getMethod] (which is inherited) and only use it internally ? I know that Objective-C doesn't exactly implement this, but I know there are tricks, such as declaring and implementing a method in the implementation file only.
另外,我如何才能不允许直接调用[self getMethod](它是继承的)而只在内部使用它呢?我知道Objective-C没有实现这个,但是我知道有一些技巧,比如只在实现文件中声明和实现一个方法。
EDIT#1:
编辑# 1:
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
我试过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);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
这只需调用继承的方法。尝试与super一起使用它只会产生一个错误。在这一点上,我将继续使用super在block中,并尝试和配置文件以查看它是否会导致任何保留周期。
EDIT#2:
编辑# 2:
Based on newacct's answer, this is what I ended up doing:
根据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);
}
I am hoping this should avoid any retain cycles, although I haven't actually profiled it yet.
我希望这能避免任何保留周期,尽管我还没有实际地介绍它。
1 个解决方案
#1
5
I know that calling [self methodName] from within a block will lead to a retain cycle.
我知道从一个块中调用[self methodName]将会导致一个retain cycle。
That is not true in general. The block will retain self
, yes. But there will only be a "retain cycle" if self
somehow retains the block. In this case, it does.
这在一般情况下是不正确的。block将保留self,是的。但是只有当self以某种方式保留了block时,才会有一个“retain cycle”。在这种情况下,确实如此。
but will super be retained
但将超级保留
Yes, self
will be retained (super
is a call on self
with a different method lookup pathway).
是的,self将被保留(super是对self的调用,使用不同的方法查找路径)。
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
我试过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);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
这只需调用继承的方法。尝试与super一起使用它只会产生一个错误。在这一点上,我将继续使用super在block中,并尝试和配置文件以查看它是否会导致任何保留周期。
There are many wrong points here. First, as said above, super
is a call on self
(there is no such thing as a super
object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self
.
这里有很多错误的地方。首先,如上所述,super是对self的调用(不存在超对象),因此在超类中获取方法的IMP并调用self就足够了。
BUT, [super methodForSelector:...
does not get the method in the superclass. It actually gets the method in this class. The super
in [super methodForSelector:...
affects which methodForSelector:
method is called. However, no class ever overrides methodForSelector:
, so there is actually no difference between [super methodForSelector:...
and [self methodForSelector:...
. As said above, super
calls the method on self
, so it still finds the method based on the class of the current object.
但是,[超级methodForSelector:…不获取超类中的方法。它会得到这个类中的方法。super in [super methodForSelector:…影响调用哪个methodForSelector: method。然而,从来没有类覆盖methodForSelector:,因此[super methodForSelector:…]之间实际上没有区别。和[自我methodForSelector:....如上所述,super对self调用方法,因此它仍然基于当前对象的类查找方法。
You can get the right IMP by using the class method +instanceMethodForSelector:
:
您可以使用类方法+instanceMethodForSelector:::
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class]
will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
但是,如果当前对象是子类的实例,则不能正确地使用上面的方法,因为[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);
It is also possible to do it using objc_msgSendSuper
directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.
也可以直接使用objc_msgSendSuper,但是这个函数也不是很容易使用。所以我认为你应该坚持上面的IMP方法。
#1
5
I know that calling [self methodName] from within a block will lead to a retain cycle.
我知道从一个块中调用[self methodName]将会导致一个retain cycle。
That is not true in general. The block will retain self
, yes. But there will only be a "retain cycle" if self
somehow retains the block. In this case, it does.
这在一般情况下是不正确的。block将保留self,是的。但是只有当self以某种方式保留了block时,才会有一个“retain cycle”。在这种情况下,确实如此。
but will super be retained
但将超级保留
Yes, self
will be retained (super
is a call on self
with a different method lookup pathway).
是的,self将被保留(super是对self的调用,使用不同的方法查找路径)。
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
我试过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);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
这只需调用继承的方法。尝试与super一起使用它只会产生一个错误。在这一点上,我将继续使用super在block中,并尝试和配置文件以查看它是否会导致任何保留周期。
There are many wrong points here. First, as said above, super
is a call on self
(there is no such thing as a super
object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self
.
这里有很多错误的地方。首先,如上所述,super是对self的调用(不存在超对象),因此在超类中获取方法的IMP并调用self就足够了。
BUT, [super methodForSelector:...
does not get the method in the superclass. It actually gets the method in this class. The super
in [super methodForSelector:...
affects which methodForSelector:
method is called. However, no class ever overrides methodForSelector:
, so there is actually no difference between [super methodForSelector:...
and [self methodForSelector:...
. As said above, super
calls the method on self
, so it still finds the method based on the class of the current object.
但是,[超级methodForSelector:…不获取超类中的方法。它会得到这个类中的方法。super in [super methodForSelector:…影响调用哪个methodForSelector: method。然而,从来没有类覆盖methodForSelector:,因此[super methodForSelector:…]之间实际上没有区别。和[自我methodForSelector:....如上所述,super对self调用方法,因此它仍然基于当前对象的类查找方法。
You can get the right IMP by using the class method +instanceMethodForSelector:
:
您可以使用类方法+instanceMethodForSelector:::
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class]
will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
但是,如果当前对象是子类的实例,则不能正确地使用上面的方法,因为[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);
It is also possible to do it using objc_msgSendSuper
directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.
也可以直接使用objc_msgSendSuper,但是这个函数也不是很容易使用。所以我认为你应该坚持上面的IMP方法。