为什么使用“selector”会导致编译器警告,但@selector(selector)不会?

时间:2016-03-02 16:28:19

标签: objective-c memory-management clang automatic-ref-counting selector

我正在搞乱,只是尝试实现一个简单的非块/委托回调函数。

Class A.m
@implementation noblocks
-(void)logSomethingAndNotify:(id)object andCallSelector:(SEL)selector {

    //some task
    NSLog(@"TRYING THIS OUT");

    //implement callback functionality
    if ([object respondsToSelector:@selector(selector)]) {
        [object performSelector:@selector(selector) withObject:object];
    }

}

@end

Class B.m
- (void)viewDidLoad {
    [super viewDidLoad];
    ClassA *noblock = [noblocks new];
    [ClassA logSomethingAndNotify:self andCallSelector:@selector(addSubviewAfterDelay)];
}

-(void)addSubviewAfterDelay {
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 100, 100)];
        view.backgroundColor = [UIColor blueColor];
        [self.view addSubview:view];
    });
}

在A类的实现文件中,如果我更改此语句:

if ([object respondsToSelector:@selector(selector)]) {            
[object performSelector:@selector(selector) withObject:object];
   }

以选择器的方式表示为方法参数

if ([object respondsToSelector:selector]) {
[object performSelector:selector withObject:object];
}

然后我从编译器收到内存泄漏警告。

我理解,鉴于Objective-C的动态运行时,向无人对象发送无选择器消息可能会有问题 - 我们不知道方法的返回类型,也不能确定我们应该保留返回的对象(如果有的话)。我理解的是为什么使用performSelector:@selector(selector)vs只使用performSelector:selector DOES NOT 导致任何ARC警告。

这个问题与其他解决编译器警告的问题并不重复 - 我的问题不在于为什么错误显示的原因与为什么ONE方式显示警告而其他方式没有显示错误。

2 个答案:

答案 0 :(得分:2)

@selector(selector)并没有按照您的想法行事。 :)

考虑:

    SEL selector = @selector(hash);
    NSLog(@"%s %s", selector, @selector(selector));

这输出(依赖于SEL实际上是一个char *作为一个实现细节,你不应该在这样的实验之外依赖它):

   asdfasdfa[71281:7385265] hash selector

@selector(selector)生成一个不会触发ARC内存警告的常量值,因为编译器可以适当地推断代码路径。

即。考虑:

    SEL bob = @selector(dobbs);
    NSLog(@"%s %s", bob, @selector(bob));

产地:

    asdfasdfa[71313:7394673] hobbs bob

变量 bob引用SEL dobbs,而@selector(bob)生成SEL bob。< / p>

答案 1 :(得分:0)

在动态选择器值上使用performSelector:时出现警告的原因是,在Cocoa内存管理中,某些方法意味着返回一个保留的(+1)实例(即它将是调用者& #39;有责任释放它)。默认情况下,这是名称以allocretainnewcopymutableCopy开头的方法。所有其他方法返回一个非保留的实例(或保留和自动释放;任何不需要调用者释放的东西)。

performSelector:,其名称并不暗示返回保留的实例,并且未使用ns_returns_retained进行注释。因此,ARC会认为它不会返回保留的实例(如果您使用它来执行&#34;普通&#34;方法,这是正确的)。但是因为我们在编译时不知道选择器是什么,所以可能是你传递了一个返回保留实例的选择器,其中它将是错误的并导致泄漏。

如果选择器在编译时是硬编码的,编译器可以在编译时检查名称,并验证它不是返回保留实例的名称之一。