开发者

Probelem with NSTimer

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];      
}


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];


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.


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];
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜