iOS - 如何实现具有多个参数和 afterDelay 的 PerformSelector?

发布于 2024-12-20 19:20:24 字数 448 浏览 2 评论 0原文

我是一名 iOS 新手。我有一个选择器方法如下 -

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

我正在尝试实现类似的东西 -

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

但这给了我一个错误 -

Instance method -performSelector:withObject:withObject:afterDelay: not found

关于我缺少什么的任何想法?

I am an iOS newbie. I have a selector method as follows -

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

I am trying to implement something like this -

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

But that gives me an error saying -

Instance method -performSelector:withObject:withObject:afterDelay: not found

Any ideas as to what I am missing?

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

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

发布评论

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

评论(11

锦上情书 2024-12-27 19:20:24

就我个人而言,我认为更接近您的需求的解决方案是使用 NSInitation。

像下面这样的东西就可以完成工作:

indexPathdataSource是在同一方法中定义的两个实例变量。

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");

if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];

    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation

    [inv invoke];
}

Personally, I think that a closer solution to your needs is the use of NSInvocation.

Something like the following will do the work:

indexPath and dataSource are two instance variables defined in the same method.

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");

if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];

    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation

    [inv invoke];
}
我的鱼塘能养鲲 2024-12-27 19:20:24

因为不存在 [NSObject PerformSelector:withObject:withObject:afterDelay:] 方法。

您需要将要发送的数据封装到某个单一 Objective C 对象中(例如 NSArray、NSDictionary、某些自定义 Objective C 类型),然后通过[NSObject PerformSelector:withObject:afterDelay:]< /code> 众所周知且喜爱的方法。

例如:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];

Because there is no such thing as a [NSObject performSelector:withObject:withObject:afterDelay:] method.

You need to encapsulate the data you want to send along into some single Objective C object (e.g. a NSArray, a NSDictionary, some custom Objective C type) and then pass it through the[NSObject performSelector:withObject:afterDelay:] method that is well known and loved.

For example:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];
阳光下慵懒的猫 2024-12-27 19:20:24

您可以将参数打包到一个对象中,并使用辅助方法来调用原始方法,正如 Michael 和其他人现在所建议的那样。

另一个选项是dispatch_after,它将获取一个块并在某个时间将其排队。

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    [self fooFirstInput:first secondInput:second];

});

或者,正如您已经发现的,如果您不需要延迟,则可以使用 -performSelector:withObject:withObject:

You can package your parameters into one object and use a helper method to call your original method as Michael, and others now, have suggested.

Another option is dispatch_after, which will take a block and enqueue it at a certain time.

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    [self fooFirstInput:first secondInput:second];

});

Or, as you've already discovered, if you don't require the delay you can just use - performSelector:withObject:withObject:

凤舞天涯 2024-12-27 19:20:24

最简单的选择是修改您的方法以采用包含两个参数的单个参数,例如 NSArrayNSDictionary (或者添加第二个采用单个参数的方法,解包它,并调用第一个方法,然后延迟调用第二方法)。

例如,您可以有类似的内容:

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

然后要调用它,您可以执行以下操作:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];

The simplest option is to modify your method to take a single parameter containing both arguments, such as an NSArray or NSDictionary (or add a second method that takes a single parameter, unpacks it, and calls the first method, and then call the second method on a delay).

For instance, you could have something like:

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

And then to call it, you can do:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];
未央 2024-12-27 19:20:24
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}


- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

并用以下方式调用它:

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}


- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

and call it with:

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
美胚控场 2024-12-27 19:20:24

您可以在此处找到提供的所有类型的performSelector:方法:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

有很多变体,但没有一个版本可以接受多个对象以及延迟。您需要将参数包装在 NSArray 或 NSDictionary 中。

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject: 

You can find all the types of provided performSelector: methods here:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

There are a bunch of variations but there isn't a version that takes multiple objects as well as a delay. You'll need to wrap up your arguments in an NSArray or NSDictionary instead.

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject: 
z祗昰~ 2024-12-27 19:20:24

我不喜欢 NSInitation 方式,太复杂了。让我们保持简单和干净:

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;

// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];

// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);

I dislike the NSInvocation way, too complex. Let’s keep it simple and clean:

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;

// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];

// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);
猫烠⑼条掵仅有一顆心 2024-12-27 19:20:24

我只是做了一些调整,需要调用原始方法。我所做的就是制定一个协议并将我的对象投射到它。
另一种方法是在类别中定义方法,但需要抑制警告(#pragma clang Diagnostic 忽略“-Wincomplete-implementation”)。

I just did some swizzling and needed to call the original method. What I did was making a protocol and cast my object to it.
Another way is to define the method in a category, but would need suppression of a warning (#pragma clang diagnostic ignored "-Wincomplete-implementation").

去了角落 2024-12-27 19:20:24

一种简单且可重用的方法是扩展 NSObject 并实现

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;

如下内容:

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
    NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
    [invocation setSelector: aSelector];

    int index = 2; //0 and 1 reserved
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}

A simple and reusable way is to extend NSObject and implement

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;

something like:

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
    NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
    [invocation setSelector: aSelector];

    int index = 2; //0 and 1 reserved
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}
草莓味的萝莉 2024-12-27 19:20:24

我只需创建一个自定义对象,将所有参数保存为属性,然后使用该单个对象作为参数

I would just create a custom object holding all my parameters as properties, and then use that single object as the parameter

Smile简单爱 2024-12-27 19:20:24

对于单个参数

perform(#selector(fuctionOne(_:)), with: arg1, afterDelay: 2)
@objc func fuctionOne(_ arg1: NSUserActivity) {
    // Do Something
}

对于多个参数

perform(#selector(fuctionTwo(_:_:)), with: [arg1, arg2], afterDelay: 2)
@objc func fuctionTwo(_ arg1: URL, _ arg2: [UIApplication.OpenURLOptionsKey: Any] = [:]) {
    // Do Something
}

For Single argument

perform(#selector(fuctionOne(_:)), with: arg1, afterDelay: 2)
@objc func fuctionOne(_ arg1: NSUserActivity) {
    // Do Something
}

For Multiple arguments

perform(#selector(fuctionTwo(_:_:)), with: [arg1, arg2], afterDelay: 2)
@objc func fuctionTwo(_ arg1: URL, _ arg2: [UIApplication.OpenURLOptionsKey: Any] = [:]) {
    // Do Something
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文