使用NSTimer传递原始参数的正确方法

时间:2010-07-16 05:55:33

标签: objective-c cocoa cocoa-touch nstimer

我正在使用调用此方法的基本计时器:

- (void) refresh:(id)obj
{
    if (obj == YES) doSomething;
}

我想从我的代码的某些区域以及计时器

中调用此方法
[NSTimer scheduledTimerWithTimeInterval:refreshInterval
                            target:self
                            selector:@selector(refresh:) 
                            userInfo:nil 
                            repeats:YES];

当我将YES作为userInfo参数的参数时,我收到EXC_BAD_ACCESS错误;这是为什么?

有人可以帮助我以正确的方式做到这一点,这样就没有丑陋的演员吗?

3 个答案:

答案 0 :(得分:10)

userInfo参数必须是对象;它是键入的idYES是一个原语,即值1。为了确保userInfo对象不被取消分配,计时器会保留它。因此,当您通过YES时,NSTimer正在执行[(id)YES retain]。在您自己的代码中尝试,看看会发生什么。 :-P

作为Documentation状态,您为方法指定的选择器必须具有签名

- (void)timerFireMethod:(NSTimer*)theTimer

这意味着您不能让NSTimer只调用任何方法 - 至少不是直接调用。您可以使用上述签名创建一个特殊方法,然后调用您想要的任何方法。

所以,假设您有一个名为refresh:的方法,并且您希望每隔一段时间调用它一次,并将其传递给YES。你可以这样做:

// somewhere
{
    [NSTimer scheduledTimerWithTimeInterval:refreshInterval
                                     target:self
                                   selector:@selector(invokeRefresh:)
                                   userInfo:nil
                                    repeats:YES];
}

- (void)invokeRefresh:(NSTimer *)timer {
    [self refresh:YES];
}

- (void)refresh:(BOOL)flag {
    if (flag) {
        // do something
    }
}

答案 1 :(得分:4)

在Objective-C中,基本类型不是对象。因此,您无法直接将其传递给期望id的参数,该参数代表通用对象。您需要将其包装到NSNumber对象中。

使用

NSTimer*timer=[NSTimer scheduledTimerWithTimeInterval:refreshInterval
                                 target:self
                               selector:@selector(refresh:) 
                               userInfo:[NSNumber numberWithBool:YES]
                                repeats:YES];

- (void) refresh:(NSTimer*)timer
{
    NSNumber* shouldDoSomething=[timer userInfo];
    if ([shouldDoSomething boolValue]) doSomething;
}

一旦完成,不要忘记使计时器无效并释放。

顺便说一句,您不必将BOOL(或C ++ bool)与YEStrue或其他内容进行比较。当你写

if(a>b) { ... }

a>b评估为bool,if使用结果。你在那里做的就像

if((a>b)==YES) { ... }

这对我来说很奇怪。并不是(..)之后的if应该包含比较;它应该包含一个布尔。

答案 2 :(得分:0)

作为kperryua答案的后续内容,如果您想通过userInfo传递原语,可以使用NSNumberNSValue将其打包;在布尔值的情况下,您需要使用[NSNumber numberWithBool:YES],然后在计时器回调中调用boolValue以获取原语。