FSN 是一个在 iOS 上用于 HTTP 网络的小型库。它包含一个类 FSNConnection 和几个小的 Cocoa Foundation 类别。FSNConnection 使用 NSConnection、blocks 以及 NSConnection 的操作队列代理或 GCD。
FSNConnection 提供以下功能
NSURL *url = ...; // required
NSDictionary *headers = ...; // optional
NSDictionary *parameters = ...; // optional
FSNConnection *connection =
[FSNConnection withUrl:url
method:FSNRequestMethodGET
headers:headers
parameters:parameters
parseBlock:^id(FSNConnection *c, NSError **error) {
return [c.responseData dictionaryFromJSONWithError:error];
}
completionBlock:^(FSNConnection *c) {
NSLog(@"complete: %@\n error: %@\n parseResult: %@\n", c, c.error, c.parseResult);
}
progressBlock:^(FSNConnection *c) {
NSLog(@"progress: %@: %.2f/%.2f", c, c.uploadProgress, c.downloadProgress);
}];
[connection start];
此模式最重要的方面
例如, foursquare 应用定义了一个 FSNConnection 的类别,看起来如下
@implementation FSNConnection (FS)
// convenience accessor property that casts parseResult to our custom, API-specific type.
- (ApiResult *)apiResult {
return self.parseResult;
}
- (ApiResult *)makeApiResultWithError:(NSError **)error {
// parse the foursquare API result JSON.
// then check self.response.statusCode, as well as the foursquare API result 'meta' JSON dict for errors.
// if everything is OK, then return the an ApiResult instance, which contains api-specific properties.
// otherwise, set *error and return nil.
...
}
// wrap an arbitrary completionBlock with standard handling behavior.
- (void)finishWithBlock:(FSNCompletionBlock)completionBlock displayError:(BOOL)displayError {
ASSERT_MAIN_THREAD;
if (self.error) {
// debug-build only error reporting.
FSLog(@"request error: %@ -- %@ -- %@ -- %@",
self.error, self.apiResult.errorDetail, self.apiResult.errorMessage, self.apiResult.errorType);
}
// perform custom block
if (completionBlock) {
completionBlock(self);
}
if (self.error && displayError) {
// display standard error UI.
...
}
// send standard notifications last.
...
}
// most foursquare API requests are constructed with this method.
// it standardizes some elements of request construction, and passes through custom parameters.
// note how we wrap the custom completionBlock with standard behavior by virtue of an intermediate method;
// this allows us to precisely control when the custom callback happens.
+ (id)withEndpoint:(NSString *)endpoint
method:(FSNRequestMethod)method
parameters:(NSDictionary *)parameters
displayError:(BOOL)displayError
parseBlock:(FSNParseBlock)parseBlock
completionBlock:(FSNCompletionBlock)completionBlock {
// note: FSAPI is a singleton defining API-related properties, defined elsewhere.
return [self withUrl:[[FSAPI shared] urlForEndpoint:endpoint]
method:method
headers:[FSAPI shared].standardRequestHeaders // headers are the same for every request
parameters:[[FSAPI shared] completeParameters:parameters] // add standard parameters like OAuth token
parseBlock:parseBlock
completionBlock:^(FSNConnection *c) {
[c finishWithBlock:completionBlock displayError:displayError];
}
progressBlock:nil];
}
// a second wrapper constructor standardizes parseBlock implementa
// most requests are constructed with this method.
+ (id)withEndpoint:(NSString*)endpoint
method:(FSNRequestMethod)method
parameters:(NSDictionary*)parameters
displayError:(BOOL)displayError
completionBlock:(FSNCompletionBlock)completionBlock {
return [self withEndpoint:endpoint
method:method
parameters:parameters
displayError:displayError
parseBlock:^(FSNConnection *c, NSError **error) {
return [c makeApiResultWithError:error];
}
completionBlock:completionBlock];
}
@end
使用与 GET 相同的类和调用进行 POST 请求。这种一致性是库最令人满意的方面之一。POST 参数值可以是三种类型之一:NSString、NSNumber 和 FSNData。
这种设计使我们能够快速适应不断变化的 Web API 要求,同时最大限度地减少代码更改,并简化表单请求的实现。
例如,照片上传可能如下所示
UIImage *originalImage = ...;
// form file name and parameter name would be determined by the web API
NSDictionary *parameters =
[NSDictionary dictionaryWithObjectsAndKeys:
[FSNData withImage:originalImage jpegQuality:.75 fileName:@"fileName"], @"paramName",
nil];
FSNConnection *connection =
[FSNConnection withUrl:url
method:FSNRequestMethodPOST
headers:headers
parameters:parameters
parseBlock:nil
completionBlock:nil
progressBlock:nil];
FSNData类有多个构造函数用于发送原始NSData;更多详细信息请查看头文件。MIME类型以枚举形式表示,旨在鼓励遵循标准并降低字符串字面量中存在错误的风险。当前,只有两种MIME类型被枚举,但可以轻松添加更多;只需在FSNData.h和FSNData.m中定义额外的枚举及其对应的字符串即可。
其他HTTP方法,如HEAD和PUT尚不支持,但添加它们不应困难。欢迎提出补丁;如果您想讨论实现方式,请随时联系。
FSNDemo-iOS演示了如何设置与四平方API的单一连接。
FSNDemo-mac展示了如何从命令行建立同样的连接。
FSN根据Apache许可证版本2.0发布;请参阅license.txt。更多信息请见以下链接
当前版本是1.0。该代码已在四平方应用的生产环境中使用多年。
存在对NSURLConnection的setDelegateQueue的支持,但默认情况下是禁用的,因为它会导致iOS 5应用程序死锁。相反,FSN使用主线程来进行连接回调和GCD在后台线程上执行解析。将FSN_QUEUED_CONNECTIONS定义为1(通常在prefix header中)来使用代理队列。
由于代理队列在狮子(Lion)中似乎运行良好,Mac演示确实使用了代理队列。但是,这已被最少测试。如果您启用此功能并发现错误,请提交补丁!
另请参阅
使用NSRecursiveLock来保护parseBlock在并发使用中防止取消/重新分配。我们更愿意有一个无锁实现以简化流程,并欢迎使用任何审查或建议更好的解决方案。
FSNetworking只依赖于Cocoa的Foundation框架;使用UIKit的便利方法已适当保护。我们目前针对iOS 5.0构建,使用最新公开发行的Xcode工具集。Mac演示针对OS X 10.7构建。
FSNConnection最初由Foursquare Labs开发,作为我们iOS应用程序中的ASIHTTPRequest的替代品。我们现在在四平方iOS应用程序的所有HTTP网络中使用它。
当前的维护者是
欢迎反馈、错误报告和代码贡献!