我通常想知道如何让迅速的代表在除主线程之外的专用线程中运行。
更具体地说,我当前正在使用HueSDK4EDK建立我的应用程序与Hue桥的连接。该过程的一部分是定义状态观察者和连接观察者(作为委托)以处理传入事件。
private func buildBridge(withBridge bridge : BridgeInfoModel) -> PHSBridge {
return PHSBridge.init(block: { (builder) in
...
builder?.bridgeConnectionObserver = self
builder?.add(self)
}, withAppName: AppBundleName, withDeviceName: DeviceName)
}
委托是在扩展中实现的,例如连接观察器:
extension HueApiManager : PHSBridgeConnectionObserver {
func bridgeConnection(_ bridgeConnection: PHSBridgeConnection!, handle connectionEvent: PHSBridgeConnectionEvent) {
...
}
}
由于连接观察器中的某些代码可能会占用大量时间,因此我想知道是否有比这更优雅的方法:
func bridgeConnection(_ bridgeConnection: PHSBridgeConnection!, handle connectionEvent: PHSBridgeConnectionEvent) {
let apiThread = DispatchQueue.global(qos: .utility)
apiThread.async {
...
}
}
非常感谢!
答案 0 :(得分:2)
是:
let apiThread = DispatchQueue.global(qos: .utility)
func bridgeConnection(_ bridgeConnection: PHSBridgeConnection!, handle connectionEvent: PHSBridgeConnectionEvent) {
apiQueue.async {
...
}
}
没有理由每次都获取队列;您可以将其存储为属性。
我知道这不是您要考虑的,但这是最好的方法。只需在需要时执行调度即可。
可以使用forwardInvocation:
构建与您在ObjC中实际想到的东西类似的东西,但是它不能很好地转换为Swift(底层机器无法在Swift中实现),我不推荐它。蹦床是一个对象(有时是NSProxy
对象),可以接受任何消息,对其执行某些操作(例如将其移至另一个队列),然后将其重新分发给另一个对象。问题是很难告诉编译器“相信我,这将在运行时实现您需要的所有方法”(因为您实际上无法承诺,因此可能会崩溃)。即使在ObjC中,这些问题通常也比他们应承担的麻烦多得多,而首先值得承担这些麻烦的唯一原因是ObjC并不总是具有GCD或块,并且在添加块时,语法是头痛。在Swift中,它要简单得多。只需添加.async
调用即可。
不过,只是为了说明蹦床的样子,这是使用操作队列(非常类似于调度队列)的样子。这是用ARC之前的ObjC编写的,不应视为现代ObjC的示例。
#import <Foundation/Foundation.h>
@interface OperationQueueInvocationTrampoline : NSObject
{
@private
NSOperationQueue *myQueue;
id myTarget;
}
- (id)initWithQueue:(NSOperationQueue *)queue;
@end
#import "OperationQueueInvocationTrampoline.h"
@interface OperationQueueInvocationTrampoline ()
@property (nonatomic, readwrite, retain) NSOperationQueue *queue;
@property (nonatomic, readwrite, assign) id target;
@end
@implementation OperationQueueInvocationTrampoline
@synthesize queue = myQueue;
@synthesize target = myTarget;
- (id)initWithQueue:(NSOperationQueue *)queue
{
self = [super init];
if (self != nil)
{
self.queue = queue;
}
return self;
}
- (void)dealloc
{
[myQueue release];
myQueue = nil;
myTarget = nil;
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
return [self.target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation setTarget:self.target];
self.target = nil;
NSOperation *operation = [[[NSInvocationOperation alloc] initWithInvocation:invocation] autorelease];
[self.queue addOperation:operation];
}
- (id)prepareWithInvocationTarget:(id)target
{
self.target = target;
return self;
}
@end
您将像这样使用它:
id delegate = [[OperationQueueInvocationTrampoline alloc] initWithTarget:self];
[otherThing setDelegate:delegate];
当大多数协议都是非正式的时,这种方法工作得很好(因此这里没有类型检查,您可以通过id
),但是在没有警告的情况下进行编译变得越来越麻烦了,而且今天在Swift中肯定是头疼的事情。它必须省去很多麻烦,但事实并非如此。
(附带说明:队列与线程不是一回事。眼前的问题是队列将事物分派到什么队列,而不是它们在什么线程上运行。)
答案 1 :(得分:0)
I don't think this is possible unless that library specifically supports it.
One thing you could do is create a "proxy" delegate class that forwards all delegate method calls on a specific DispatchQueue.
It's not a perfect solution, but at least you can keep your HueApiManager a bit cleaner because you do not need apiThread.async
everywhere.
class DelegateProxy: PHSBridgeConnectionObserver {
weak var delegate: PHSBridgeConnectionObserver?
var queue = DispatchQueue.global(qos: .utility)
func bridgeConnection(_ bridgeConnection: PHSBridgeConnection!, handle connectionEvent: PHSBridgeConnectionEvent) {
queue.async {
delegate?.bridgeConnection(bridgeConnection, handle: connectionEvent)
}
}
// Other delegate methods...
}