NSTimer 的问题

发布于 2024-09-11 05:57:29 字数 2398 浏览 1 评论 0原文

我的 NSTimer 有问题。 我收到“SIGABRT”错误和 [NSCFTimer intValue]: 无法识别的选择器发送到实例

这是我的代码:

-(void)detectionMove:(NSNumber*)arrayIndex{


    static BOOL notFind = FALSE;
    static int countVariable = 0;
    static int countRilevamenti = 0;

    notFind = FALSE;

    for(int i = countVariable+1; i<[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]count]; i++){

        if(!notFind){

            if((actualAccelerometerX+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueX] && (actualAccelerometerX-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueX] &&
               (actualAccelerometerY+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueY] && (actualAccelerometerY-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueY] &&
               (actualAccelerometerZ+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueZ] && (actualAccelerometerZ-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueZ])
            {
                countVariable = i;
                notFind = TRUE;
                countRilevamenti++;
            }
        }
    }

    if(!notFind)
        return;

    else if(countVariable+1 == [[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]]  arrayPositionMove]count]){

        if(countRilevamenti + tollerance >= [[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]count])
            movementDetected = [arrayIndex intValue];
        else
            NSLog(@"troppo veloce");

        countVariable = 0;
        notFind = FALSE;
        countRilevamenti = 0;       

        return;
    }

    [NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(detectionMove:) userInfo:(NSNumber*)arrayIndex repeats:NO];      
}

I have a problem with a NSTimer.
I received a "SIGABRT" error and [NSCFTimer intValue]: unrecognized selector sent to instance

These is my code:

-(void)detectionMove:(NSNumber*)arrayIndex{


    static BOOL notFind = FALSE;
    static int countVariable = 0;
    static int countRilevamenti = 0;

    notFind = FALSE;

    for(int i = countVariable+1; i<[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]count]; i++){

        if(!notFind){

            if((actualAccelerometerX+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueX] && (actualAccelerometerX-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueX] &&
               (actualAccelerometerY+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueY] && (actualAccelerometerY-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueY] &&
               (actualAccelerometerZ+sensibilityMovement) >= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueZ] && (actualAccelerometerZ-sensibilityMovement) <= [[[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]objectAtIndex:i]valueZ])
            {
                countVariable = i;
                notFind = TRUE;
                countRilevamenti++;
            }
        }
    }

    if(!notFind)
        return;

    else if(countVariable+1 == [[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]]  arrayPositionMove]count]){

        if(countRilevamenti + tollerance >= [[[[sharedController arrayMovement]objectAtIndex:[arrayIndex intValue]] arrayPositionMove]count])
            movementDetected = [arrayIndex intValue];
        else
            NSLog(@"troppo veloce");

        countVariable = 0;
        notFind = FALSE;
        countRilevamenti = 0;       

        return;
    }

    [NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(detectionMove:) userInfo:(NSNumber*)arrayIndex repeats:NO];      
}

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

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

发布评论

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

评论(3

焚却相思 2024-09-18 05:57:29

您的方法签名错误,

- (void)timerFireMethod:(NSTimer*)theTimer

而不是 NSNumber

--edit2--

NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];  
[myDictionary setObject:arrayIndex forKey:@"index"];
[NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(detectionMove:) userInfo:myDictionary repeats:NO];  

--edit--

如果您想保留旧方法,以便可以使用 NSNumber< 从其他地方调用它/code> 参数,您必须创建一个新方法供 NSTimer 调用,然后在 NSTimer 方法的实现中调用 NSNumber方法与任何合适的数字。

-(void)detectionMove:(NSNumber*)arrayIndex{
 // still does whatever
}

-(void)automaticDetectionMove:(NSTimer*)theTimer{
 [self detectionMove:whatevernumber];
}

// update with new method name
[NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(automaticDetectionMove:) userInfo:(NSNumber*)arrayIndex repeats:NO];

You have the wrong signature for your method

- (void)timerFireMethod:(NSTimer*)theTimer

not NSNumber

--edit2--

NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];  
[myDictionary setObject:arrayIndex forKey:@"index"];
[NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(detectionMove:) userInfo:myDictionary repeats:NO];  

--edit--

If you want to keep your old method so you can call it from somewhere else with a NSNumber argument you have to create a new method for the NSTimer to call and then in the implementation of the NSTimer method you call the NSNumber method with whatever number that is appropriate.

-(void)detectionMove:(NSNumber*)arrayIndex{
 // still does whatever
}

-(void)automaticDetectionMove:(NSTimer*)theTimer{
 [self detectionMove:whatevernumber];
}

// update with new method name
[NSTimer scheduledTimerWithTimeInterval:timeToCatch target:self selector:@selector(automaticDetectionMove:) userInfo:(NSNumber*)arrayIndex repeats:NO];
奈何桥上唱咆哮 2024-09-18 05:57:29

NSTimer 触发方法必须具有签名:

- (void)myMethod:(NSTimer *)timer;

计时器将其自身作为参数传递给您设置的方法。

如果您需要额外的参数,请将它们设置在用户信息字典中,然后使用它们的密钥检索它们:

[[timer userInfo] objectForKey:@"myUserInfoParamterKey"];

因此作为示例,您应该在用户信息中设置 NSNumber 对象并检索它方式,不将其作为参数传递给计时器方法。

NSTimer fire methods must have the signature:

- (void)myMethod:(NSTimer *)timer;

The timer passes itself as an argument to the method you set.

If you want extra parameters, set them in the user info dictionary, and then retrieve them using their key using:

[[timer userInfo] objectForKey:@"myUserInfoParamterKey"];

So as an example, you should be setting your NSNumber object in your user info and retrieving it that way, not passing it as a parameter to the timer method.

古镇旧梦 2024-09-18 05:57:29

正如其他几个答案所指出的, NSTimer 签名是

- (void)methodName:(NSTimer *)timer;

如果您需要有时直接调用方法,有时通过计时器(或者可能使用包含所需参数键的字典)调用方法,而不是包装,您可能想要考虑添加一组辅助宏以放入项目 .pch 文件中,

#define ifThenElse(_if_,_then_,_else_) ( (_if_) ? _then_ : _else_ )

#define isClass(objectToTest,isOfClass) ifThenElse(objectToTest==nil,NO,[objectToTest isKindOfClass:[isOfClass class]])

#define asClass(object,requiredClass) \
/**/ifThenElse(isClass(object,requiredClass),\
/*****/((requiredClass *)object),\
/****/nil\
/***/)


#define asClassViaMethod(object,requiredClass,viaClass,viaMethod) \
/**/ifThenElse(isClass(object,requiredClass),\
/*****/(requiredClass *)object,\
/*****/ifThenElse(isClass(object,viaClass),\
/*********/(requiredClass *)[(viaClass*)object viaMethod],\
/*********/nil)\
/***/)

使用它们的方式相对简单,而且恕我直言,与将函数包装 3 次以考虑变体调用相比,代码更具可读性。

但首先是一些关于它如何工作的背景信息。

您的计时器方法选择器可以以最基本的形式非常安全地表达,

- (void)myMethod:(id)sender;

而不会发生任何令人讨厌的事情。这意味着“sender”没有对象类型,如果不将其转换为您期望的类型,您就无法用它做很多事情。
然而,在安全地进行强制转换之前,您需要确定该对象的类型正确。

这就是宏的帮助之处,因为它们通过一系列测试来包装发送者,过滤掉不正确的类型并返回 nil,而不是允许您将不正确的选择器发送到无法响应它的对象。请注意,宏本身可以用更简洁的方式表达,但是为了理解它们是如何工作的,并且没有任何性能开销,我选择用注释来表达它们。您始终可以修剪它们,但是没有真正的性能优势,因为它们将产生相同的编译输出。

理论使用示例:

NSTimer 接收者 - 您希望使用 NSNumber,但计时器会自行发送给您。

- (void)myMethod:(id)sender{
    NSNumber *argument = asClassViaMethod(sender,NSNumber,NSTimer,userInfo);


}

UIGestureRecognizer 接收者 - 您希望使用视图,通过GR 自行向您发送。

- (void)myMethod:(id)sender{
    NSNumber *argument = asClassViaMethod(sender,UIView,UIGestureRecognizer,view);


}

您正在扩展但不想破坏它的自定义方法
它曾经是:

- (void)myMethod:(NSNumber *)number{
     [myOtherObject setNumber:number];
}

但现在需要一个 NSNumber &一个 NSString,而不仅仅是一个 NSNumber。有时您也可能只想向其发送一个 NSString 本身

调整的方法标头和参数解析器

- (void)myMethod:(id)sender{

    NSNumber *number = asClassViaMethod(sender,UIView,NSDictionary,objectForKey:@"number");
    NSNumber *string = asClassViaMethod(sender,UIView,NSDictionary,objectForKey:@"string");

    if (number) {
       // do something funky with number
    }

    if (string) {
       // do something funky with string
    }

}

现实世界使用示例从我的项目之一剪切和粘贴:

NSInteger artistIndex = asClassViaMethod(artistIndex_, NSNumber, NSTimer, userInfo).integerValue;

...

NSDictionary *payload = asClassViaMethod(sender,NSDictionary,NSTimer,userInfo);

附注,当您想要直接调用该方法而不需要包装器的灵活性时,这是向计时器方法发送多个参数的一种便捷方法……

UIView *tappee = asClassViaMethod(sender,UIView,UITapGestureRecognizer,view);

    for (id element in connectArray) {
        NSURL *url                  =  asClassViaMethod(element, NSURL,   NSDictionary, objectForKey:@"url");
        NSArray *additionalHeaders  =  asClassViaMethod(element, NSArray, NSDictionary, objectForKey:@"headers");


        NSString *path = [url path];
        NSString *query = [url query];
        if (query.length) {
            path = [[url path] stringByAppendingFormat:@"?%@",query];
        }


        [self requestDocument:path additionalHeaders:additionalHeaders];
    }

最后一个示例中,如果数组包含 NSURL,它使用它,“additionalHeaders”被解析为nil。
如果数组包含一个包含 NSURL 的 NSDictionary 和一个分别带有键 @"url" 和 @"headers" 的 NSArray,则它使用提供的值。

最后,如果不明显,请调用您的计时器方法

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(myMethod:) userInfo:[NSNumber numberWithInteger:myNSInteger] repeats:NO];

...或...

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(myMethod:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys: myNSNumber,@"number",myNSString,@"string",nil] repeats:NO];

as pointed out by several other answers, the NSTimer signature is

- (void)methodName:(NSTimer *)timer;

if you need to call a method sometimes directly, sometimes via a timer (or perhaps with dictionary that contains a key to the argument you need), rather than wrapping, you may want to consider adding a set of helper macros to put in your project .pch file

#define ifThenElse(_if_,_then_,_else_) ( (_if_) ? _then_ : _else_ )

#define isClass(objectToTest,isOfClass) ifThenElse(objectToTest==nil,NO,[objectToTest isKindOfClass:[isOfClass class]])

#define asClass(object,requiredClass) \
/**/ifThenElse(isClass(object,requiredClass),\
/*****/((requiredClass *)object),\
/****/nil\
/***/)


#define asClassViaMethod(object,requiredClass,viaClass,viaMethod) \
/**/ifThenElse(isClass(object,requiredClass),\
/*****/(requiredClass *)object,\
/*****/ifThenElse(isClass(object,viaClass),\
/*********/(requiredClass *)[(viaClass*)object viaMethod],\
/*********/nil)\
/***/)

the way you use them is relatively simple, and imho makes for more readable code than wrapping a function 3 times to account for variant invocations.

but first some background info on how it works.

your timer method selector can be expressed quite safely in it's most basic form,

- (void)myMethod:(id)sender;

without anything nasty happening on the way. all it means is that "sender" has no object type, and you can't do a lot with it, without casting it to the type you expect it to be.
before you can safely cast however, you need to know for sure that the object is of the correct type.

thats where the macros help in that they wrap the sender with a series of tests that filters out incorrect types and return nil instead of allowing you to send an incorrect selector to an object that can't respond to it. please note that the macros themselves can be expressed in a more concise manner, however for understanding how they work, and without any performance overhead, i have chosen to express them longhand with comments. you can always trim them down, however there is no real performance benefit, as they will result in the same compiled output.

theoretical use examples:

NSTimer recipient - you want an NSNumber to work with, but timer sends you itself.

- (void)myMethod:(id)sender{
    NSNumber *argument = asClassViaMethod(sender,NSNumber,NSTimer,userInfo);


}

UIGestureRecognizer recipient - you want the view to work with, by GR sends you itself.

- (void)myMethod:(id)sender{
    NSNumber *argument = asClassViaMethod(sender,UIView,UIGestureRecognizer,view);


}

Custom method you are extending, but don't want to break it
it used to be:

- (void)myMethod:(NSNumber *)number{
     [myOtherObject setNumber:number];
}

but it now needs an NSNumber & an NSString, instead of just an NSNumber. you also may sometimes just want to send it an NSString by itself

adjusted method header and argument parsers

- (void)myMethod:(id)sender{

    NSNumber *number = asClassViaMethod(sender,UIView,NSDictionary,objectForKey:@"number");
    NSNumber *string = asClassViaMethod(sender,UIView,NSDictionary,objectForKey:@"string");

    if (number) {
       // do something funky with number
    }

    if (string) {
       // do something funky with string
    }

}

real world use examples cut and paste from one of my projects:

NSInteger artistIndex = asClassViaMethod(artistIndex_, NSNumber, NSTimer, userInfo).integerValue;

...

NSDictionary *payload = asClassViaMethod(sender,NSDictionary,NSTimer,userInfo);

as a side note, this is a handy way of sending multiple parameters to a timer method, when you want the flexibility of calling that method directly, without a wrapper...

UIView *tappee = asClassViaMethod(sender,UIView,UITapGestureRecognizer,view);

...

    for (id element in connectArray) {
        NSURL *url                  =  asClassViaMethod(element, NSURL,   NSDictionary, objectForKey:@"url");
        NSArray *additionalHeaders  =  asClassViaMethod(element, NSArray, NSDictionary, objectForKey:@"headers");


        NSString *path = [url path];
        NSString *query = [url query];
        if (query.length) {
            path = [[url path] stringByAppendingFormat:@"?%@",query];
        }


        [self requestDocument:path additionalHeaders:additionalHeaders];
    }

in this last example, if the array contains an NSURL, it uses that, with "additionalHeaders" being resolved to nil.
if the array contains an NSDictionary containing an NSURL and an NSArray with the keys @"url" and @"headers" respectively, it uses the supplied values.

finally, in case it's not obvious, calling your timer method

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(myMethod:) userInfo:[NSNumber numberWithInteger:myNSInteger] repeats:NO];

... or ...

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(myMethod:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys: myNSNumber,@"number",myNSString,@"string",nil] repeats:NO];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文