背景:
我有一个对象(我们称之为BackendClient
)代表了与服务器的连接。它的方法生成为单个@protocol
,并且它们都是同步的,因此我想创建代理对象,该对象将在后台调用它们。主要问题是返回值,我显然不能从异步方法返回它,因此我需要传递一个回调。 “简单”的方法是复制所有BackendClient
的方法并添加回调参数。但这不是解决该问题的动态方法,而ObjectiveC本质是动态的。那就是performSelector:
出现的地方。它完全解决了问题,但是几乎杀死了代理对象的透明性。
问题:
我希望能够将未声明的选择器发送到代理(NSProxy
的子类)对象,就好像它已经声明过一样。
例如,我有方法:
-(AuthResponse)authByRequest:(AuthRequest*)request
在
BackendClient
协议中。我希望代理 call 如下所示:[proxyClient authByRequest:myRequest withCallback:myCallback];
但这不会编译,因为
“BackendClientProxy”没有可见的@interface声明选择器“authByRequest:withCallBack:”
好。让我们稍微放松一下编译器:
[(id)proxyClient authByRequest:myRequest withCallback:myCallback];
Awww。另一个错误:
选择器'authByRequest:withCallBack:'的未知实例方法
我唯一想到的一点是,在运行时以某种方式用所需的方法构造了新的
@protocol
,但是我不知道该怎么做。结论:我需要消除此编译错误。任何想法如何做到这一点?
最佳答案
据我了解,您有一个同步的,非线程的,想要异步的API,以便不阻塞主事件循环等。
我要向BackgroundClient添加一个串行队列:
@property(strong) dispatch_queue_t serialQueue;
... somewhere in your -init ...
_serialQueue = dispatch_queue_create(..., serial constant);
然后:
- (void)dispatchOperation:(dispatch_block_t)anOperation
{
dispatch_async(_serialQueue, anOperation);
}
可以这样使用:
[myClient dispatchOperation:^{
[myClient doSynchronousA];
id result = [myClient doSynchronousB];
dispatch_async(dispatch_get_main_queue(), ^{
[someone updateUIWithResult:result];
}
}];
这是将BackgroundClient移到异步模型而无需重写或大量重构的最简单方法。
如果要加强API,请为BackendClient创建一个类包装器,其中包含客户端实例和串行队列。使得所述类实例化客户端,而其余代码仅从该包装中检索实例。这将使您仍然具有相同的
dispatchOperation:
模型,但不需要镜像所有方法。typedef void(^ AsyncBackendBlock(BackendClient * bc);
@interface AsyncBackend
+(instancetype)asyncBackendWithBackend:(BackendClient *)bc;
@property .... serialQueue;
- (void) dispatchAsync:(AsyncBackendBlock) backBlock;
@end
.m:
@interface AsyncBackend()
@property... BackendClient *client;
@end
@implementation AsyncBackend
- (void) dispatchAsync:(AsyncBackendBlock) backBlock
{
dispatch_async(_serialQueue, ^{
backBlock(_client);
});
}
@end
call 者:
AsyncBackend *b = [AsyncBackend asyncBackendWithBackend:[BackendClient new]];
[b dispatchAsync:^(BackendClient *bc) {
[bc doSomething];
id result = [bc retrieveSomething];
dispatch_async(dispatch_get_main_queue(), ^{
[uiThingy updateWithResult:result];
}
}];
....
关于ios - 没有performSelector:如何发送未声明的选择器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18553901/