简体   繁体   English

ObjC + Cocoa中的回调

[英]Callbacks in ObjC+Cocoa

I'm relatively new to Cocoa/ObjC. 我是可可/ ObjC的新手。 Could someone please help me change my code to use asynchronous network calls? 有人可以帮我更改代码以使用异步网络调用吗? Currently it looks like this (fictional example): 当前看起来像这样(虚构示例):

// Networker.m
-(AttackResult*)attack:(Charactor*)target {
    // prepare attack information to be sent to server
    ServerData *data = ...;
    id resultData = [self sendToServer:data];
    // extract and return the result of the attack as an AttackResult
}

-(MoveResult*)moveTo:(NSPoint*)point {
    // prepare move information to be sent to server
    ServerData *data = ...;
    id resultData = [self sendToServer:data];
    // extract and return the result of the movement as a MoveResult
}


-(ServerData*)sendToServer:(ServerData*)data {
    // json encoding, etc
    [NSURLConnection sendSynchronousRequest:request ...]; // (A)
    // json decoding
    // extract and return result of the action or request
}

Notice that for each action (attack, move, etc), the Networker class has logic to convert to and from ServerData. 请注意,对于每个动作(攻击,移动等),Networker类都有逻辑来与ServerData进行相互转换。 It is unacceptable to expect the other classes in my code to deal with this ServerData. 期望我代码中的其他类都可以处理此ServerData是不可接受的。

I need to make line A an asynchronous call. 我需要使A行成为异步调用。 It seems that the correct way to do this is to use [NSURLConnection connectionWithRequest:...delegate:...] implementing a callback to do the post-processing. 似乎正确的方法是使用[NSURLConnection connectionWithRequest:... delegate:...]实现回调以进行后处理。 This is the only way I can think to do it: 这是我可以想到的唯一方法:

//Networker.m
-(void)attack:(Charactor*)target delegate:(id)delegate {
    // prepare attack information to be sent to server
    ServerData *data = ...;
    self._currRequestType = @"ATTACK";
    self._currRequestDelegate = delegate;
    [self sendToServer:data];
    // extract and return the result of the attack
}

-(void)moveTo:(NSPoint*)point delegate:(id)delegate {
    // prepare move information to be sent to server
    ServerData *data = ...;
    self._currRequestType = @"MOVE";
    self._currRequestDelegate = delegate;
    [self sendToServer:data];
    // extract and return the result of the movement
}


-(void)sendToServer:(ServerData*)data {
    // json encoding, etc
    [NSURLConnection connectionWithRequest:...delegate:self] // (A)
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //json decoding, etc
    switch( self._currRequestType ) {
        case @"ATTACK": {...} // extract and return the result of the attack in a callback
        case @"MOVE": {...} // extract and return the result of the move in a callback
    }
}

However, this is very ugly and not thread safe. 但是,这非常难看并且不是线程安全的。 What is the proper way to do this? 正确的方法是什么?

Thanks, 谢谢,

One option is to have one object instance per command/request; 一种选择是每个命令/请求有一个对象实例。 as an added bonus you can then use subclasses so that the handling of the type is polymorphic, rather than based on a big switch statement. 另外,您可以使用子类,以便对类型进行多态处理,而不是基于大的switch语句。 Make a base command object with an initWithDelegate: method (then have specialized inits in the subclasses corresponding to commands that need arguments) and methods for the basic sending/receiving plumbing. 使用initWithDelegate:方法(然后在需要参数的命令所对应的子类中具有专门的init)和用于基本发送/接收管道的方法来创建基本命令对象。 Each subclass can implement a handleResponse: or similar that's called from your baseclass connectionDidFinishLoading:. 每个子类都可以实现handleResponse:或从基类connectionDidFinishLoading:中调用的类似方法。

If you want to hide that from the clients of this service, your attack:, moveTo:, etc. methods can hide the instantiation of these objects, so the clients would be interacting with the same API. 如果要从该服务的客户端中隐藏它们,那么Attack:,moveTo:等方法可以隐藏这些对象的实例化,因此客户端将与同一API进行交互。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM