FSNetworking 0.0.1

FSNetworking 0.0.1

测试已测试
语言语言 Obj-CObjective C
许可证 自定义
发布最后发布2014年12月

Donald Burr 维护。



  • Bryan Bonczek

foursquare 的 iOS 网络库

FSN 是一个在 iOS 上用于 HTTP 网络的小型库。它包含一个类 FSNConnection 和几个小的 Cocoa Foundation 类别。FSNConnection 使用 NSConnection、blocks 以及 NSConnection 的操作队列代理或 GCD。

功能

FSNConnection 提供以下功能

  • 异步 HTTP 和 HTTPS 请求。
  • GET 和 POST(urlencoded 和表单数据);易于扩展其他 HTTP 方法。
  • 在后台线程上解析响应,然后主线程上的完成块。
  • 方便、安全的对象保留语义和生命周期管理,支持一键请求。
  • 支持 iOS 背景任务。
  • 用于创建和调试表单数据、解析 JSON、错误检查等的有用工具。
  • 干净、直观的实现;没有需要理解的类层次结构。易于跟踪和理解连接的生命周期!

示例

GET

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];

此模式最重要的方面

  • 从解析块返回的值被分配给连接的 parseResult 属性。
  • 同样,如果解析块设置了任何错误,那么它将被分配给连接的 error 属性。
  • 您可以为该方法编写简单的包装器以适应 Web API 中的所有端点
    • 为每个端点组合一个 URL。
    • 发送标准头,如 User-Agent 和 Accept-Language。
    • 发送标准参数,如 OAuth 令牌、客户端版本等。
    • 通过在执行一致错误检查、解析等操作的包装块内调用小的自定义块来组合标准和自定义的解析和完成步骤。

例如, 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

POST

使用与 GET 相同的类和调用进行 POST 请求。这种一致性是库最令人满意的方面之一。POST 参数值可以是三种类型之一:NSString、NSNumber 和 FSNData。

  • 如果 POST 只包含 NSString 和 NSNumber 值,则它将具有内容类型 "application/x-www-form-urlencoded"。
  • 如果任何参数是 FSNData 对象,则请求将具有内容类型 "multipart/form-data"。

这种设计使我们能够快速适应不断变化的 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方法。

其他HTTP方法,如HEAD和PUT尚不支持,但添加它们不应困难。欢迎提出补丁;如果您想讨论实现方式,请随时联系。

演示

FSNDemo-iOS演示了如何设置与四平方API的单一连接。

  • 目前,由于OAuth错误,连接将失败,展示了错误处理约定。
  • 要看到成功的连接,请在http://developer.foursquare.com注册OAuth令牌,或者只需请求一个静态HTML页面。

FSNDemo-mac展示了如何从命令行建立同样的连接。

  • 运行异步连接需要程序手动运行主runloop。

许可证

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网络中使用它。

当前的维护者是

欢迎反馈、错误报告和代码贡献!