AFNetworking 回调 - 委托还是通知?
Posted
技术标签:
【中文标题】AFNetworking 回调 - 委托还是通知?【英文标题】:AFNetworking callbacks - delegate or notification? 【发布时间】:2015-03-17 15:15:52 【问题描述】:我对将 AFNetworking 结果发送到控制器的最佳方式或正确方式有疑问。是通过委托还是通知?
我创建了一个类来处理具有以下代码的 API 调用。因此,如果将此类导入另一个控制器并调用此方法进行 API 调用。我应该委托还是通知?
我已阅读 www.raywenderlich.com/59255/afnetworking-2-0-tutorial,它正在使用委托。我还观看了 CodeSchool 教程,他们使用了从模型到控制器的通知。
我添加了下面的代码,希望能更好地展示我的问题。
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
// notification way inside the BLOCK
[ manager GET:path parameters:params
success:^(NSURLSessionDataTask *operation, id responseObject)
[ [NSNotificationCenter defaultCenter] postNotificationName:notificationName
object:nil
userInfo:responseObject ];
failure:^(NSURLSessionDataTask *operation, NSError *error)
[ [NSNotificationCenter defaultCenter] postNotificationName:notificationName
object:nil ];
];
// delegate way inside the BLOCK
[ manager GET:path parameters:params
success:^(NSURLSessionDataTask *operation, id responseObject)
if ([delegate respondsToSelector:@selector(getUserFeedsDidFinish:resultDict:)])
[delegate performSelector:@selector(getUserFeedsDidFinish:resultDict:) withObject:self withObject:resultDict];
failure:^(NSURLSessionDataTask *operation, NSError *error)
if ([delegate respondsToSelector:@selector(getUserFeeds:didFailWithResultDict:)])
[delegate performSelector:@selector(getUserFeeds:didFailWithResultDict:)
withObject:self
withObject:[NSDictionary dictionaryWithObject:error.userInfo forKey:KEY_ERRORS]];
];
【问题讨论】:
【参考方案1】:我会推荐使用积木,如何?我给你写一个服务,这个写在一个叫Connection的类里:
+(void)requestLocation:(NSString*)googleReference completionBlock:(void (^)(NSString * coordinates, NSError * error)) handler
NSString * urlString = @"https://maps.googleapis.com/maps/";
NSMutableDictionary * parametersDictionary = [NSMutableDictionary dictionary];
[parametersDictionary setObject:googleReference forKey:@"reference"];
[parametersDictionary setObject:@"true" forKey:@"sensor"];
[parametersDictionary setObject:@"key(it is not)" forKey:@"key"];
AFHTTPClient *HTTPClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:urlString]];
NSURLRequest *URLRequest = [HTTPClient requestWithMethod:@"GET" path:@"api/place/details/json" parameters:parametersDictionary];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:URLRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
NSError * error = nil;
NSDictionary * response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:&error];
NSDictionary * dicGeo = [((NSDictionary*)[response objectForKey:@"result"]) objectForKey:@"geometry"];
NSDictionary * coords = [dicGeo objectForKey:@"location"];
NSNumber * lat = [coords objectForKey:@"lat"];
NSNumber * lng = [coords objectForKey:@"lng"];
NSString * coordinates = [NSString stringWithFormat:@"%@,%@", lat.description, lng.description];
handler(coordinates, error);
failure:^(AFHTTPRequestOperation *operation, NSError *error)
NSLog(@"%@", error);
];
[requestOperation start];
然后调用这个服务:
[Connection requestLocation:@"google reference (it is not)" completionBlock:^(NSString *coordinates, NSError *error)
//Your code with results.
【讨论】:
我认为 AFJSONRequestOperation 现在不在 AFNetworking 之下:***.com/questions/21294178/… 您应该使用响应序列号:operation.responseSerializer = [AFJSONResponseSerializer serializer];
但无论如何:您的代码必须使用 AFNetworking 1.x,因为 AFHTTPClient 在 AFNetworking 2 中不可用。
链接中的答案也建议这样做。【参考方案2】:
我只是接触了 AFNetworking 的皮毛。从我所见,大部分似乎都使用了第三种方法,块。
块有点新,与委托和通知不同。
块是 C 函数指针的扩展,可让您在调用方法时将代码传递给方法。
使用块的常见设计模式是创建一个采用完成块的方法。完成块是在异步请求完成时调用的一段代码。
以AFNewtworking方法HTTPRequestOperationWithRequest为例。该方法接受一个成功块,如果请求成功则调用它,以及一个失败块,如果请求失败则调用它。
【讨论】:
【参考方案3】:阻止是使用 IMO 的最简单方法。您不需要实现额外的委托方法,也不需要任何构造。
基本上像这样定义你的包装器。
typedef void(^SampleRequestCompletion)(NSError *error, id data);
- (void)GET:(NSString *)URLString
parameters:(NSDictionary *)parameters
completion:(SampleRequestCompletion)completion
[self GET:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
// Do what you want
if (completion)
completion(nil, data);
failure:^(AFHTTPRequestOperation *operation, NSError *error)
// Failure case
if (completion)
completion(error,nil);
];
并从这样的任何对象调用此方法,
[self GET:path parameters:dictionary completion:^(NSError *error, id data)
];
因此,您可以管理呼叫以成功或失败结束时要执行的操作。
【讨论】:
【参考方案4】:按照教程的建议,我们可以将 Web 服务相关的代码提取到一个更像模型级别的模块中。考虑到网络模块和视图之间的通信,视图在单例 Web 服务客户端上调用/启动请求,一旦响应返回,通常的工作流程就会将结果发送到视图控制器并在视图中显示数据。我们不需要将任何东西返回给网络模块。
所以这个工作流程更像是一个通知而不是委托。并将 V 设置为 M 的代表,这很奇怪。
通知:嘿,伙计,我已经完成了我的工作,轮到你了。 代表团:嘿,伙计,我做了很多,现在我需要你掩护/备份/提供一些任务,然后我会继续/完成工作。
在某些情况下,很难选择哪个更好。对于 AFNetworking,我认为 Notification 方法更好。
【讨论】:
通知不能说“嘿你”,因为不知道谁在听。它是一种广播机制。委托也涵盖了网络,正如网络委托人可能会说的:“我已经完成了获取。委托,做任何你想做的事”。苹果自己的网络课程就是这样工作的。另外 networqking 不属于模型,而是控制器。但不是视图控制器。 是的,您可能对网络模块是否属于控制器是正确的。但正如教程所示,我们可以继承 AFNetworking 类并将 Web 服务抽象为一个模块。由于大多数 Web 服务更像是一个数据源,恕我直言,至少我们可以将服务模块视为模型,我们只需通过定义的接口获取/放置(读/写)数据,而不管模块是网络的还是持久的。在 Unix 世界中,我们可以使用相同的进程从网络或文件中读取数据。 对于通知或委托,我仍在调查,但目前我选择了通知。我们不能仅仅因为 Apple 使用委托而缩小范围。在我的实践中,通知将获得更简洁的代码,并且如果您要更改设计,则可以将调用者和被调用者解耦,尤其是在参数上。使用字典比使用显式参数更方便。我刚刚从我的经验中得到这些,我发现有时我需要更改委托方法签名。如果你有更好的实践,你会分享更多细节吗?提前谢谢你。 正如所有其他海报所说:块。 谢谢!在做了一些实验后,我发现块可能是另一种选择。听起来我需要更好地设计代码结构来解耦错误处理。以上是关于AFNetworking 回调 - 委托还是通知?的主要内容,如果未能解决你的问题,请参考以下文章
swift 2:与objective-c相比,推送通知没有委托回调
NSURLConnection(作为 AFNetworking 的一部分)不调用 NSURLConnectionDataDelegate 委托