RBEFireworks 1.0.0

RBEFireworks 1.0.0

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2016年8月

robbie 维护。



  • Robbie

RBEFireworks(英)

RBEFireworks 是一个功能丰富且灵活的库。它处理网络组件的常见需求,使得网络请求的编程变得更加容易。基于 AFNetworking3.x(NSURLSession),它达到了更高的抽象级别,并参考了 YTKNetwork 的启发性思想。

在此特别感谢 AFNetworkingYTKNetwork,因为您的开源资源对于社区来说是无穷无尽的财富。

RBEFireworks 架构设计的原则是简洁,这使得您更易使用。它感觉就像原生 Apple 库,只要您有 NSURLSession 和 NSURLRequest 的知识,这个库就可以非常迅速地全面为您服务。它将网络请求抽象成全新对象,提供强大的可表达性,并且非常方便重用。

RBEFireworks 希望您的网络请求像烟花一样绽放,并能成为永恒的回忆!

中国朋友可以看这里,RBEFireworks(中文)

功能

  • 取消和恢复请求
  • 恢复下载请求
  • 带有更友好界面设计的上传请求
  • 上传和下载请求进度回调
  • 链式请求,一组请求相互有依赖关系。
  • 批量请求,一组独立请求。
  • 新鲜缓存,基于内存和磁盘的高性能缓存,采用 LRU 算法。
  • 统一预处理请求参数,例如,添加设备类型。
  • 统一处理请求响应,例如,根据业务判断请求是否成功或失败。
  • 统一处理请求 URL,例如,添加服务 API 版本。
  • 验证响应数据类型是否符合您的期望。
  • 支持 Block 和 Delegate 回调。
  • 扩展请求,例如,添加加载,计请求持续时间。
  • 统一处理 NSHTTPCookie 和 NSURLCache。

要求

iOS8.0+

与所需库和框架链接

libsqlite3.tbd

安装

$ pod RBEFireworks

基本配置

在使用 RBEFireworks 之前,您需要配置 URL 设置。您可以设置基础 URL 或设置 CDN URL。

    [RBEFireworkAdapter sharedInstance].baseURL = @"DemoProjectBaseURL";
    [RBEFireworkAdapter sharedInstance].CDNURL = @"DemoProjectCDNURL";

基本用法

要恢复GET请求,您应该提供相对URL。

    RBEFirework *firework = [[RBEFirework alloc] initWithRelativeURL:@"demo"];
    [firework resume];

要恢复POST请求。要恢复不同的HTTP方法请求,只需提供不同的枚举值。

    RBEFirework *firework = [[RBEFirework alloc] initWithRelativeURL:@"demo" 
                                                          parameters:@{@"demo" : @"demo"} 
                                                          HTTPMethod:RBEHTTPMethodPost];
    [firework resumeWithSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
        //succes to do...
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //failure to do...
    }];

要恢复链式请求,您应该提供一个包含请求的数组。链式请求按照数组顺序执行请求。如果一个请求失败,则不会执行后续请求。

    RBEFirework *demoOne = [[RBEFirework alloc] initWithRelativeURL:@"demoOne"];
    RBEFirework *demoTwo = [[RBEFirework alloc] initWithRelativeURL:@"demoTwo"];
    RBEFirework *demoThree = [[RBEFirework alloc] initWithRelativeURL:@"demoThree"];

    RBEChainFirework *chain = [[RBEChainFirework alloc] initWithFireworkArray:@[demoOne, demoTwo, demoThree]];
    [chain resumeWithSuccessBlock:^(RBEChainFirework * _Nonnull chainFirework) {
        RBEFirework *successOne = [chainFirework.fireworkArr firstObject];
        NSDictionary *successDicOne = successOne.responseObject;
        if (successDicOne) {
            //first successed...
        }

        RBEFirework *successTwo = chainFirework.fireworkArr[1];
        NSDictionary *successDicTwo = successTwo.responseObject;
        if (successDicTwo) {
            //second successed...
        }

        RBEFirework *successThree = [chainFirework.fireworkArr lastObject];
        NSDictionary *successDicThree = successThree.responseObject;
        if (successDicThree) {
            //third successed...
        }

    } failureBlock:^(RBEChainFirework * _Nonnull chainFirework, RBEFirework * _Nonnull failedFirework) {
        if ([failedFirework isEqualToFirework:[chainFirework.fireworkArr firstObject]]) {
            //first failed...
        } else if ([failedFirework isEqualToFirework:chainFirework.fireworkArr[1]]) {
            //second failed...
        } else {
            //third failed...
        }
    }];

要恢复批量请求,除了请求数组之外,您还需要决定如果某个请求失败,是否取消其他请求。默认为否。

    RBEFirework *demoOne = [[RBEFirework alloc] initWithRelativeURL:@"demoOne"];
    RBEFirework *demoTwo = [[RBEFirework alloc] initWithRelativeURL:@"demoTwo"];
    RBEFirework *demoThree = [[RBEFirework alloc] initWithRelativeURL:@"demoThree"];

    [demoOne setSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
        //first successed...
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //first failed...
    }];

    [demoTwo setSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
        //second successed...
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //second failed...
    }];

    [demoThree setSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
        //third successed...
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //third failed...
    }];

    RBEBatchFirework *batch = [[RBEBatchFirework alloc] initWithFireworkArray:@[demoOne, demoTwo, demoThree] shouldCancelAllFireworkIfOneFireworkFailed:NO];
    [batch resume];

如果您偏好回调函数,则可以使用此协议组。

//Firework success
- (void)fireworkFinished:(RBEFirework *)firework {}
//Firework fail
- (void)fireworkFailed:(RBEFirework *)firework {}
//Chain Firework success
- (void)chainFireworkFinished:(RBEChainFirework *)chainFirework {}
//Chain Firework fail
- (void)chainFireworkFailed:(RBEChainFirework *)chainFirework failedFirework:(RBEFirework *)firework {}
//Batch Firework success
- (void)batchFireworkFinished:(RBEBatchFirework *)batchFirework {}
//Batch Firework fail
- (void)batchFireworkFailed:(RBEBatchFirework *)batchFirework failedFireworks:(NSArray<RBEFirework *> *)failedFireworks {}

统一配置

您可以通过遵守 RBEURLAdapterProtocol 并实现 adaptedURL: 函数来统一过滤URL。

您也可以通过遵守 RBEParametersAdapterProtocol 并实现 adaptedParametersWithOriginalParameters: 函数来统一过滤参数。

@interface DemoURLFilter : NSObject <RBEURLAdapterProtocol>

@end

@implementation DemoURLFilter

- (NSString *)adaptedURL:(NSString *)originURL {
    if ([originURL hasPrefix:@"demo"]) {
        return [originURL stringByAppendingString:@"/v1"];
    } else {
        return originURL;
    }
}

@end

@interface DemoParametersFilter : NSObject <RBEParametersAdapterProtocol>

@end

@implementation DemoParametersFilter

- (id)adaptedParametersWithOriginalParameters:(id)parameters {
    if (parameters) {
        NSMutableDictionary *paraDic = parameters;
        [paraDic setObject:@(1) forKey:@"type"];
        parameters = paraDic;
    }else {
        parameters = [[NSMutableDictionary alloc] init];
        [parameters setObject:@(1) forKey:@"type"];
    }

    return parameters;
}

@end

然后编写以下代码

    //Adapte Parameters
    DemoParametersFilter *paramFilter = [[DemoParametersFilter alloc] init];
    [[RBEFireworkAdapter sharedInstance] addParamterAdapters:paramFilter];

    //Adapte URL
    DemoURLFilter *URLFilter = [[DemoURLFilter alloc] init];
    [[RBEFireworkAdapter sharedInstance] addURLAdapters:URLFilter];

您还可以统一决定请求调用成功、失败或忽略。如果您决定忽略请求,请求将不会执行成功的完成块或失败的完成块。

    [RBEFireworkAdapter sharedInstance].validateBlock = ^(RBEFirework *responseFirework) {
        RBEFireworkResponseType responseType = RBEFireworkResponseTypeSuccess;

        NSDictionary *responseDic = responseFirework.responseObject;
        if (responseDic) {
            NSNumber *code = responseDic[@"code"];

            if ([code isEqualToNumber:@0]) {
                //success
            } else if ([code isEqualToNumber:@1]) {
                responseType = RBEFireworkResponseTypeFailure;
            } else {
                responseType = RBEFireworkResponseTypeIgnore;
            }
        }
        return responseType;
    };

您可以通过RBEFireworkAdapter设置或获取Cookie。

    [[RBEFireworkAdapter sharedInstance] setCookieWithCookieDomain:@".demo.com"
                       cookieOriginUrl:nil
                            cookieName:@"demo"
                           cookieValue:@"demo_value"
                            cookiePath:@"/"
                         cookieVersion:nil
                         cookieExpires:nil];
    NSHTTPCookie *cookie = [[RBEFireworkAdapter sharedInstance] cookieWithcookieName:@"demo"];

缓存

RBEFireworks中存在两种缓存模式。一种是HTTP缓存模式,另一种是新鲜度缓存模式。您可以通过更改 cachePattern 属性来影响缓存模式。

HTTP缓存模式使用 NSURLCache 实现,基本上就是根据HTTP标准缓存请求。您也可以更改 RBEFireworkAdapter 的 customCachedURLResponse 属性以提供自定义实现。

新鲜度缓存模式使用 RBECache 实现,您需要更改 cacheFreshnessInSecond 属性来提供缓存的存活时间,单位为秒。如果缓存未过期,则表示缓存是新鲜的,请求将不会实际恢复。如果缓存已过期,则表示缓存已过时,请求将实际恢复。

或者,您可以将 cachePattern 属性更改为 RBECachePatternNone,以禁用任何模式缓存。默认为 RBECachePatternNone

您应该通过 RBEFireworkAdapter 启用任何模式缓存。您需要提供缓存的目录,以及在内存和磁盘中的缓存容量。尽管,HTTP缓存模式的容量单位为字节,而新鲜度缓存模式的容量单位为要缓存的请求数量。

    NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];

    //For Freshness Cache
    NSString *freshnessCacheDir = [cacheDirectory stringByAppendingPathComponent:@"FreshnessCache"];
    [[RBEFireworkAdapter sharedInstance] enableCacheWithFreshnessCachePatternDirectory:freshnessCacheDir freshnessMemoryCount:20 freshnessDiskCapacity:10 * 1024 * 1024];

    //For HTTP Cache
    NSString *HTTPCacheDir = [cacheDirectory stringByAppendingPathComponent:@"HTTPCache"];
    [[RBEFireworkAdapter sharedInstance] enableCacheWithHTTPCachePatternDirectory:HTTPCacheDir HTTPMemoryCapacity:2 * 1024 * 1024 HTTPDiskCapacity:10 * 1024 * 1024];

清除所有缓存或清除内存中的缓存。

    //clear memory cache
    [[RBEFireworkAdapter sharedInstance] purgeInMemoryCache];
    //clear memory cache and disk cache
    [[RBEFireworkAdapter sharedInstance] purgeAllCache];

您还可以通过调用 cachedObject 函数来获取请求的缓存。

    RBEFirework *demoOne = [[RBEFirework alloc] initWithRelativeURL:@"demoOne"];
    id cachedObject = demoOne.cachedObject;
    if (cachedObject) {
        //cache to do...
    }

上传和下载

您可以使用 RBEUploadFirework 上传数据。您初始化 RBEUploadFirework 提供的URL不是相对URL,而是绝对URL。RBEUploadFirework 使用 AFNetworking 的多部分/表单数据上传实现。

您可以为上传提供文件URL、数据 NSInputStream、数据 NSData 和 multipart/form-data 请求的正文。

    RBEUploadFirework *upload = [[RBEUploadFirework alloc] initWithUploadURL:@"demo"];
                           [upload uploadWithFileURL:[NSURL URLWithString:@"demoURL"] 
                                                name:@"demo" 
                                            fileName:@"demoFileName" 
                                            mimeType:@"demoMimeType"];

您可以使用 RBEDownloadFirework 恢复下载。您初始化 RBEDownloadFirework 提供的URL不是相对URL,而是绝对URL。

苹果的本地实现持续下载必须满足以下条件

  • GET请求
  • 服务器支持字节范围请求
  • 服务器在其响应中提供 ETag 或 Last-Modified 标头(或两者都提供)

RBEFireworks 实现的持续下载不获取 ETag 或 Last-Modified

您可以将 isProvideETagOrLastModified 属性更改为指定。默认为 YES。

    RBEDownloadFirework *download = [[RBEDownloadFirework alloc] initWithDownloadURL:@"demo" destinationPath:@"demoDestinationPath"];
    //Employ NSURLSession downloadTaskWithResumeData API or self-Implementaion
    download.isProvideETagOrLastModified = YES;
    [download resumeWithSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
        NSString *path = [download downloadedContentPath];
        if (path) {
            //Get path to do...
        }
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //failure to do...
    }];

成功后,通过调用downloadedContentPath获取实际下载内容路径。如果无法将下载内容写入您提供的路径,则下载内容将写入临时路径。因此,downloadedContentPath返回的路径可能不是您提供的路径。

RBEUploadFirework和RBEDownloadFirework可以通过修改progressBlock属性来获取进度回调。

firework.progressBlock = ^(NSProgress *progress) {
        //progress to do...
    };

更多功能

暂停和取消请求。

    [firework suspend];
    [firework cancel];

您可以通过调用breakChain函数来断开链式请求。

    RBEFirework *demoOne = [[RBEFirework alloc] initWithRelativeURL:@"demoOne"];
    [demoOne setSuccessBlock:^(RBEFirework * _Nonnull responseFirework) {
       NSDictionary *respondeDic = responseFirework.responseObject;
       if (respondeDic[@"demo"]) {
           [responseFirework breakChain];
       }
    } failureBlock:^(RBEFirework * _Nonnull responseFirework) {
        //failure to do
    }];

    RBEFirework *demoTwo = [[RBEFirework alloc] initWithRelativeURL:@"demoTwo"];

    RBEChainFirework *chain = [[RBEChainFirework alloc] initWithFireworkArray:@[demoOne, demoThree]];
    [chain resume];

您可以通过验证服务返回的响应类型是否符合您的预期。数据的名称应映射到数据类型。如果不符合,请求将失败。

    firework.responseValidator = @[@{@"demoId" : [NSString class],
                                    @"demoTime" : [NSNumber class],
                                    @"demoStuff" : @{
                                            @"demoStuffId" : [NSString class],
                                       @"demoStuffContent" : [NSString class]
                                            }
                                    }];

您可以在恢复请求之前、取消请求之前、暂停请求之前、请求执行完成块之前或之后执行任何操作。您只需遵循RBEFireworkAccessoryProtocol并实现任意函数。例如,您可以编写以下代码来显示加载状态

@interface DemoFireworkAccessory : NSObject <RBEFireworkAccessoryProtocol>

@property (nonatomic, strong) UIActivityIndicatorView *indicator;

+ (instancetype)accessory;

- (void)fireworkWillResume:(RBEFirework *)firework;

- (void)fireworkWillComplete:(RBEFirework *)firework;

@end

@implementation DemoFireworkAccessory

+ (instancetype)accessory {
    DemoFireworkAccessory *accessory = [[DemoFireworkAccessory alloc] init];
    accessory.indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    return accessory;
}

- (void)fireworkWillResume:(RBEFirework *)firework {
    [self.indicator startAnimating];
}

- (void)fireworkWillComplete:(RBEFirework *)firework {
    [self.indicator stopAnimating];
}

@end

然后编写以下代码

    DemoFireworkAccessory *accessory = [DemoFireworkAccessory accessory];
    [firework addAccessory:accessory];

您可以通过修改customRequest属性来恢复自定义请求,您提供的自定义请求将忽略RBEFirework的其他配置,除了成功和失败回调。

    firework.customRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"firework"]];

您可以通过调用RBEFireworkAdapter的以下函数来取消所有请求。这将导致NSURLSession对应配置类型的调用finishTasksAndInvalidate或invalidateAndCancel函数。

- (void)cancelAllRBEFireworkInConfigurationTpye:(RBESessionConfigurationType)configurationType  allowOutstandingTaskFinish:(BOOL)isAllow;

除了这些,您仍然可以配置AFNetworking。

@property (nonatomic, assign) RBEFireworkRequestSerializerType requestSerializerType;

@property (nonatomic, assign) RBEFireworkResponseSerializerType responseSerializerType;

//Default is application/json text/json text/javascript
@property (nonatomic, strong) NSSet<NSString *> *acceptableContentTypes;

//Default is No
@property (nonatomic, assign) BOOL allowInvalidCertificates;

第一个是请求序列化类型,默认为HTTP。第二个是响应标准化类型,默认为JSON。第三个是响应接受的内容类型,默认为application/json,text/json,text/javascript。第四个是是否允许无效的证书,默认为NO。

还有许多其他属性可进行配置,它们直接会影响NSMutableURLRequest。

@property (nonatomic, assign) NSTimeInterval timeoutInterval;
@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;
@property (nonatomic, assign) BOOL allowsCellularAccess;
@property (nonatomic, assign) BOOL HTTPShouldHandleCookies;
@property (nonatomic, assign) BOOL HTTPShouldUsePipelining;

配置类型影响请求对应的NSURLSessionConfiguration。

@property (nonatomic, assign) RBESessionConfigurationType sessionConfigurationType;

标签

@property (nonatomic, assign) NSInteger tag;
@property (nullable, nonatomic, strong) NSDictionary *userInfo;

更改HTTP头

- (void)setAuthenticationHeaderFieldWithUserName:(NSString *)userName password:(NSString *)password;

- (void)setHeaderField:(NSDictionary<NSString *, NSString *> *)headerField;

如果您想获取请求的信息,只需使用NSLog。


以上代码也在示例中演示。

最重要的是,享受乐趣!