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

发布于 2024-09-10 07:07:04 字数 569 浏览 2 评论 0原文

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

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

我想从代码的某些区域以及计时器中调用此方法

[NSTimer scheduledTimerWithTimeInterval:refreshInterval
                            target:self
                            selector:@selector(refresh:) 
                            userInfo:nil 
                            repeats:YES];

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

有人可以帮助我以正确的方式做到这一点,这样就不会有丑陋的选角之类的吗?

I'm using a basic timer that calls this method:

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

I want to call this method from certain areas of my code and also from a timer

[NSTimer scheduledTimerWithTimeInterval:refreshInterval
                            target:self
                            selector:@selector(refresh:) 
                            userInfo:nil 
                            repeats:YES];

When I put YES as the argument for the userInfo parameter, I get an EXC_BAD_ACCESS error; why is this?

Can someone help me do this the right way so that there is no ugly casting and such?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清晰传感 2024-09-17 07:07:04

userInfo 参数必须是一个对象;它的类型是idYES 是一个原语,即值 1。为了确保 userInfo 对象不会被释放,计时器会保留它。因此,当您传递 YES 时,NSTimer 正在执行 [(id)YES keep]。在您自己的代码中尝试一下,看看会发生什么。 :-P

作为 文档 规定,您为方法提供的选择器必须具有签名

- (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
    }
}

The userInfo parameter must be an object; it is typed id. YES is a primitive, namely the value 1. In order to make sure the userInfo object does not get deallocated, the timer retains it. So, when you passed YES, NSTimer was doing [(id)YES retain]. Try that in your own code and see what happens. :-P

As the Documentation states, the selector you give the method must have the signature

- (void)timerFireMethod:(NSTimer*)theTimer

This means you can't have an NSTimer invoke just any method—not directly at least. You can make a special method with the above signature which in turn invokes any method you want though.

So, say you have a method called refresh:, and you want to call it every so often, passing it YES. You can do this like so:

// 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
    }
}
如何视而不见 2024-09-17 07:07:04

在 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 之后的 (..) 应该包含比较;而是应该包含比较。它应该包含一个布尔值。

In Objective-C, a primitive type is not an object. So you can't directly pass it to an argument which expects an id, which stands for a generic object. You need to wrap it into an NSNumber object.

Use

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

and

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

Don't forget to invalidate and release the timer once it's done.

By the way, you don't have to compare a BOOL (or C++ bool) against YES or true or whatever. When you write

if(a>b) { ... }

a>b evaluates to a bool, and if uses the result. What you're doing there is like

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

which is quite strange to me. It's not that the (..) after if should contain a comparison; it should contain a bool.

渔村楼浪 2024-09-17 07:07:04

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

As a follow-up to kperryua's answer, if you want to pass a primitive through userInfo you can box it with NSNumber or NSValue; in the case of a boolean, you'd want to use [NSNumber numberWithBool:YES], then call boolValue in the timer callback to get back the primitive.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文