时间:2010-07-26 09:37:09

标签: iphone objective-c nstimer

3 个答案:

答案 0 :(得分:2)

答案 1 :(得分:1)

答案 2 :(得分:0)

正如其他几个答案所指出的那样,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)\
/***/)

你使用它们的方式相对简单,并且imho使代码更容易读取,而不是将函数包装3次以考虑变体调用。

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

你的计时器方法选择器可以用它最基本的形式表达,

- (void)myMethod:(id)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];