用两个参数在主线程上执行选择器的好方法?
Posted
技术标签:
【中文标题】用两个参数在主线程上执行选择器的好方法?【英文标题】:A nice way to perform a selector on the main thread with two parameters? 【发布时间】:2011-12-25 12:19:51 【问题描述】:我正在寻找一种在主线程上使用两个参数执行选择器的好方法
我真的很喜欢使用
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
方法,除了现在我有两个参数。
所以基本上我有一个委托,我需要在加载图像时通知它:
[delegate imageWasLoaded:(UIImage *)image fromURL:(NSString *)URLString;
但是我这样做的方法可能会在后台线程中调用,并且委托将使用此图像来更新 UI,所以这需要在主线程中完成。所以我真的希望代理也能在主线程中得到通知。
所以我看到了一个选项 - 我可以创建一个字典,这样我只有一个对象,其中包含我需要传递的两个参数。
NSDictionary *imageData = [NSDictionary dictionaryWithObjectsAndKeys:image, @"image", URLString, @"URLstring", nil];
[(NSObject *)delegate performSelectorOnMainThread:@selector(imageWasLoaded:) withObject: imageData waitUntilDone:NO];
但这种方法对我来说似乎不合适。有没有更优雅的方法来做到这一点?也许使用 NSInvocation? 提前致谢。
【问题讨论】:
【参考方案1】:在这种情况下,使用 NSDictionary 传递多个参数是正确的方法。
不过,更现代的方法是使用 GCD 和块,这样您就可以直接向对象发送消息。此外,看起来您的委托方法可能正在做一些 UI 更新;您在主线程上正确处理。使用 GCD,您可以轻松地做到这一点,并且像这样异步:
dispatch_async(dispatch_get_main_queue(), ^
[delegate imageWasLoaded:yourImage fromURL:yourString;
);
用这个替换你的performSelector:withObject
调用,你就不必为了改变你的方法签名而搞砸了。
确保你:
#import <dispatch/dispatch.h>
引入 GCD 支持。
【讨论】:
非常感谢,我想到了,但我的部署操作系统是 3.0,我不想为 ios 4.0 和 3.0 编写不同的代码。还有NSInvocation呢,这里能用吗? 真的吗? 2 操作系统落后于当前操作系统?我已经更新了标签以反映这一点。但是,如果您正在启动一个新应用,并且没有非常充分的理由为 iOS3 编写代码,那么您最好为最新的 SDK 编写代码。 好吧,不幸的是,这不是我的决定:(【参考方案2】:由于您无法访问 GCD,因此 NSInvocation 可能是您最好的选择。
NSMethodSignature *sig = [delegate methodSignatureForSelector:selector];
NSInvocation *invoke = [NSInvocation invocationWithMethodSignature:sig];
[invoke setTarget:delegate]; // argument 0
[invoke setSelector:selector]; // argument 1
[invoke setArgument:&arg1 atIndex:2]; // arguments must be stored in variables
[invoke setArgument:&arg2 atIndex:3];
[invoke retainArguments];
/* since you're sending this object to another thread, you'll need to tell it
to retain the arguments you're passing along inside it (unless you pass
waitUntilDone:YES) since this thread's autorelease pool will likely reap them
before the main thread invokes the block */
[invoke performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:NO];
【讨论】:
这是GCD之前的正确解决方案,如果要经常使用,可以轻松放入自定义方法performSelectorOnMainThread:withObject:withObject:
。
谢谢!这就是我要找的东西!
使用后是否需要释放任何东西? (由于保留了参数)【参考方案3】:
也可以使用以下方法:
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
根据此方法的文档- 在延迟后使用默认模式在当前线程上调用接收者的方法。
【讨论】:
但问题是我希望它在主线程中发送,无论它是在哪个线程中调用的【参考方案4】:是的,您的想法是正确的:您需要将要传递给主线程上的委托的所有数据封装到一个通过performSelectorOnMainThread
传递的对象中。您可以将其作为NSDictionary
对象、NSArray
对象或一些自定义的Objective C 对象传递。
【讨论】:
以上是关于用两个参数在主线程上执行选择器的好方法?的主要内容,如果未能解决你的问题,请参考以下文章
[ jquery 过滤器 find(expr|obj|ele) ] 此方法用于在选择器的基础之上搜索所有与指定表达式匹配的元素,这个函数是找出正在处理的元素的后代元素的好方法
单击 ImageView 并在 Swift/Xcode 中执行没有选择器的函数