Showing preview only (1,201K chars total). Download the full file or copy to clipboard to get everything.
Repository: knightsj/SJNetwork
Branch: master
Commit: d84100447458
Files: 134
Total size: 1.1 MB
Directory structure:
gitextract_p9vvfh07/
├── LICENSE
├── README.md
├── SJNetwork/
│ ├── SJNetwork.h
│ ├── SJNetworkBaseEngine.h
│ ├── SJNetworkBaseEngine.m
│ ├── SJNetworkCacheInfo.h
│ ├── SJNetworkCacheInfo.m
│ ├── SJNetworkCacheManager.h
│ ├── SJNetworkCacheManager.m
│ ├── SJNetworkConfig.h
│ ├── SJNetworkConfig.m
│ ├── SJNetworkDownloadEngine.h
│ ├── SJNetworkDownloadEngine.m
│ ├── SJNetworkDownloadResumeDataInfo.h
│ ├── SJNetworkDownloadResumeDataInfo.m
│ ├── SJNetworkHeader.h
│ ├── SJNetworkManager.h
│ ├── SJNetworkManager.m
│ ├── SJNetworkProtocol.h
│ ├── SJNetworkRequestEngine.h
│ ├── SJNetworkRequestEngine.m
│ ├── SJNetworkRequestModel.h
│ ├── SJNetworkRequestModel.m
│ ├── SJNetworkRequestPool.h
│ ├── SJNetworkRequestPool.m
│ ├── SJNetworkUploadEngine.h
│ ├── SJNetworkUploadEngine.m
│ ├── SJNetworkUtils.h
│ └── SJNetworkUtils.m
├── SJNetwork.podspec
└── SJNetworkDemo/
├── Podfile
├── Pods/
│ ├── AFNetworking/
│ │ ├── AFNetworking/
│ │ │ ├── AFHTTPSessionManager.h
│ │ │ ├── AFHTTPSessionManager.m
│ │ │ ├── AFNetworkReachabilityManager.h
│ │ │ ├── AFNetworkReachabilityManager.m
│ │ │ ├── AFNetworking.h
│ │ │ ├── AFSecurityPolicy.h
│ │ │ ├── AFSecurityPolicy.m
│ │ │ ├── AFURLRequestSerialization.h
│ │ │ ├── AFURLRequestSerialization.m
│ │ │ ├── AFURLResponseSerialization.h
│ │ │ ├── AFURLResponseSerialization.m
│ │ │ ├── AFURLSessionManager.h
│ │ │ └── AFURLSessionManager.m
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── UIKit+AFNetworking/
│ │ ├── AFAutoPurgingImageCache.h
│ │ ├── AFAutoPurgingImageCache.m
│ │ ├── AFImageDownloader.h
│ │ ├── AFImageDownloader.m
│ │ ├── AFNetworkActivityIndicatorManager.h
│ │ ├── AFNetworkActivityIndicatorManager.m
│ │ ├── UIActivityIndicatorView+AFNetworking.h
│ │ ├── UIActivityIndicatorView+AFNetworking.m
│ │ ├── UIButton+AFNetworking.h
│ │ ├── UIButton+AFNetworking.m
│ │ ├── UIImage+AFNetworking.h
│ │ ├── UIImageView+AFNetworking.h
│ │ ├── UIImageView+AFNetworking.m
│ │ ├── UIKit+AFNetworking.h
│ │ ├── UIProgressView+AFNetworking.h
│ │ ├── UIProgressView+AFNetworking.m
│ │ ├── UIRefreshControl+AFNetworking.h
│ │ ├── UIRefreshControl+AFNetworking.m
│ │ ├── UIWebView+AFNetworking.h
│ │ └── UIWebView+AFNetworking.m
│ ├── Pods.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── xcuserdata/
│ │ └── SunShijie.xcuserdatad/
│ │ └── xcschemes/
│ │ ├── AFNetworking.xcscheme
│ │ ├── Pods-SJNetworkingDemo.xcscheme
│ │ └── xcschememanagement.plist
│ └── Target Support Files/
│ ├── AFNetworking/
│ │ ├── AFNetworking-dummy.m
│ │ ├── AFNetworking-prefix.pch
│ │ └── AFNetworking.xcconfig
│ └── Pods-SJNetworkingDemo/
│ ├── Pods-SJNetworkingDemo-acknowledgements.markdown
│ ├── Pods-SJNetworkingDemo-acknowledgements.plist
│ ├── Pods-SJNetworkingDemo-dummy.m
│ ├── Pods-SJNetworkingDemo-frameworks.sh
│ ├── Pods-SJNetworkingDemo-resources.sh
│ ├── Pods-SJNetworkingDemo.debug.xcconfig
│ └── Pods-SJNetworkingDemo.release.xcconfig
├── SJNetworkingDemo/
│ ├── Other/
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
│ ├── SJNetwork/
│ │ ├── SJNetwork.h
│ │ ├── SJNetworkBaseEngine.h
│ │ ├── SJNetworkBaseEngine.m
│ │ ├── SJNetworkCacheInfo.h
│ │ ├── SJNetworkCacheInfo.m
│ │ ├── SJNetworkCacheManager.h
│ │ ├── SJNetworkCacheManager.m
│ │ ├── SJNetworkConfig.h
│ │ ├── SJNetworkConfig.m
│ │ ├── SJNetworkDownloadEngine.h
│ │ ├── SJNetworkDownloadEngine.m
│ │ ├── SJNetworkDownloadResumeDataInfo.h
│ │ ├── SJNetworkDownloadResumeDataInfo.m
│ │ ├── SJNetworkHeader.h
│ │ ├── SJNetworkManager.h
│ │ ├── SJNetworkManager.m
│ │ ├── SJNetworkProtocol.h
│ │ ├── SJNetworkRequestEngine.h
│ │ ├── SJNetworkRequestEngine.m
│ │ ├── SJNetworkRequestModel.h
│ │ ├── SJNetworkRequestModel.m
│ │ ├── SJNetworkRequestPool.h
│ │ ├── SJNetworkRequestPool.m
│ │ ├── SJNetworkUploadEngine.h
│ │ ├── SJNetworkUploadEngine.m
│ │ ├── SJNetworkUtils.h
│ │ └── SJNetworkUtils.m
│ └── ViewController/
│ ├── DownLoadViewController.h
│ ├── DownLoadViewController.m
│ ├── UploadViewController.h
│ ├── UploadViewController.m
│ ├── ViewController.h
│ └── ViewController.m
├── SJNetworkingDemo.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata/
│ │ └── SunShijie.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ └── SunShijie.xcuserdatad/
│ └── xcschemes/
│ ├── SJNetworkingDemo.xcscheme
│ └── xcschememanagement.plist
├── SJNetworkingDemo.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcuserdata/
│ └── SunShijie.xcuserdatad/
│ ├── UserInterfaceState (ruwang’s MacBook Air 的冲突副本 2017-11-24).xcuserstate
│ ├── UserInterfaceState (ruwang’s MacBook Air 的冲突副本 2017-11-28).xcuserstate
│ ├── UserInterfaceState.xcuserstate
│ └── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
├── SJNetworkingDemoTests/
│ ├── Info.plist
│ └── SJNetworkingDemoTests.m
└── SJNetworkingDemoUITests/
├── Info.plist
└── SJNetworkingDemoUITests.m
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 J_Knight_
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# SJNetwork




[](https://juejin.im/post/5a3f4ae8f265da4322416967)
[](https://weibo.com/1929625262/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1)
[](https://github.com/knightsj/SJNetwork/blob/master/LICENSE)
## Introduction
SJNetwork provides a high level network request API based on AFNetworking and inspired by YTKNetwork: generating network request object according to the configuration of a specific network request(url, method, parameters etc.) and managing requests by the corresponding objects.
Document for Chinese-convenient reader:[中文文档](https://juejin.im/post/5a3f4ae8f265da4322416967)
## Features
- **Ordinary request**: sending GET,POST,PUT,DELETE network request.
- write and load caches, configure cache available time duration
- **Upload request**: sending upload image(s) network request
- one and more than one image uploading and configure compress ratio before uploading
- **Download request**: sending download file network request
- resumable or not
- background downloading supporting or not
- **Default parameters**:default parameters will be added on request body
- **Custom header**: configuring custom request header(key-value)
- **Base url configuration** : server url of network requests
- **Request management**:canceling one or more than one current network requests; checking current requests' information
- **Cache operation**: writing, loading or clearing one or more than one cache of network requests ; calculating cache size
- **Debug mode switch**: for convenience of debugging
## Usage
**Method1:** using Cocoapods:
``pod 'SJNetwork'``
then
```objective-c
#import <SJNetwork/SJNetwork.h>
```
**Method2**: moving ``SJNetwork``folder into your project.
then
```objective-c
#import "SJNetwork.h"
```
### Basic Configuration
#### Server url
```objective-c
[SJNetworkConfig sharedConfig].baseUrl = @"http://v.juhe.cn";
```
#### Default parameters
```objective-c
[SJNetworkConfig sharedConfig].defailtParameters = @{@"app_version":[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"],
@"platform":@"iOS"};
```
#### Timeout seconds
```objective-c
[SJNetworkConfig sharedConfig].timeoutSeconds = 30;//default is 20s
```
#### Debug mode
```objective-c
[SJNetworkConfig sharedConfig].debugMode = YES;//default is NO
```
#### Add request header
```objective-c
[[SJNetworkConfig sharedConfig] addCustomHeader:@{@"token":@"2j4jd9s74bfm9sn3"}];
```
or
```objective-c
[[SJNetworkManager sharedManager] addCustomHeader:@{@"token":@"2j4jd9s74bfm9sn3"}];
```
> The input key-value pair will be added in network request header.
>
> If a pair with same key-value dose not exist, then add it, if it exists, then replace it.
### Ordinary Network Request
POST request (none writing or none loading cache):
```objective-c
[[SJNetworkManager sharedManager] sendPostRequest:@"toutiao/index"
parameters:@{@"type":@"top",
@"key" :@"0c60"}
success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSInteger statusCode) {
}];
```
POST request ( writing and loading cache):
```objective-c
[[SJNetworkManager sharedManager] sendPostRequest:@"toutiao/index"
parameters:@{@"type":@"top",
@"key" :@"0c60"}
loadCache:YES
cacheDuration:180
success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSInteger statusCode) {
}];
```
> If loadcache is set to be YES, then try to load cache before sending network request.
>
> If cacheDuration is set to be more than 0, then write cache after receiving response object.
Flow chart of cache operation in ordinary requests:

### Cache Operation
#### Loading cache
Loading cache of a specific network request:
```objective-c
[[SJNetworkManager sharedManager] loadCacheWithUrl:@"toutiao/index"
method:@"POST"
parameters:@{@"type":@"top",
@"key" :@"0c60"}
completionBlock:^(id _Nullable cacheObject) {
}];
```
Loading cache of network requests share the same request url:
```objective-c
[[SJNetworkManager sharedManager] loadCacheWithUrl:@"toutiao/index"
completionBlock:^(NSArray * _Nullable cacheArr) {
}];
```
Loading cache of network requests which share the same request url and method:
```objective-c
[[SJNetworkManager sharedManager] loadCacheWithUrl:@"toutiao/index"
method:@"POST"
completionBlock:^(NSArray * _Nullable cacheArr) {
}];
```
#### Clearing Cache
Clearing cache of one specific network request:
```objective-c
[[SJNetworkManager sharedManager] clearCacheWithUrl:@"toutiao/index"
method:@"POST"
parameters:@{@"type":@"top",
@"key" :@"0c60"}
completionBlock:^(BOOL isSuccess) {
}];
```
Clearing cache of network requests share the same request url:
```objective-c
[[SJNetworkManager sharedManager] clearCacheWithUrl:@"toutiao/index"
completionBlock:^(BOOL isSuccess) {
}];
```
Clearing cache of network requests which share the same request url and method:
```objective-c
[[SJNetworkManager sharedManager] clearCacheWithUrl:@"toutiao/index"
method:@"POST"
completionBlock:^(BOOL isSuccess) {
}];
```
#### Calculating Cache
Calculating the size of cache folder:
```objective-c
[[SJNetworkManager sharedManager] calculateCacheSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize, NSString *totalSizeString) {
NSLog(@"file count :%lu and total size:%lu total size string:%@",(unsigned long)fileCount,(unsigned long)totalSize, totalSizeString);
}];
```
> **fileCount**:file counts in cache folder
>
> **totalSize**: size of cache folder(unit is byte)
>
> **totalSizeString**:size of cache folder (size of unit) eg.``file count :5 and total size:1298609 total size string:1.2385 MB``
### Uploading Function
Uploading one image, original size:
```objective-c
[[SJNetworkManager sharedManager] sendUploadImageRequest:@"api"
parameters:nil
image:image_1
name:@"universe"
mimeType:@"png"
progress:^(NSProgress *uploadProgress) {
self.progressView.observedProgress = uploadProgress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSInteger statusCode, NSArray<UIImage *> *uploadFailedImages) {
}];
```
> Here, the mimeType can be jpg/JPG, png/PNG, jpeg/JPEG and if the user gives a wrong type, the mimeType will be jpg.
Uploading two images, compress ratio is 0.5(note that if the mineType is 'png' or 'PNG', the compressRatio will be useless):
```objective-c
[[SJNetworkManager sharedManager] sendUploadImagesRequest:@"api"
parameters:nil
images:@[image_1,image_2]
compressRatio:0.5
name:@"images"
mimeType:@"jpg"
progress:^(NSProgress *uploadProgress) {
self.progressView.observedProgress = uploadProgress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSInteger statusCode, NSArray<UIImage *> *uploadFailedImages) {
}];
```
And if the server which is used for uploading is **different from** the server for ordinary requests, you can user this api:
```objective-c
[[SJNetworkManager sharedManager] sendUploadImagesRequest:@"http://uploads.im/api"
ignoreBaseUrl:YES
parameters:nil
images:@[image_1,image_2]
compressRatio:0.5
name:@"images"
mimeType:@"jpg"
progress:^(NSProgress *uploadProgress) {
self.progressView.observedProgress = uploadProgress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSInteger statusCode, NSArray<UIImage *> *uploadFailedImages) {
}];
```
> Here, setting ignoreBaseUrl to be YES, and the request url should be complete download url.
### Downloading Function:
We support background downloading(using NSURLSessionDownloadTask object ) and none-background downloading(using NSURLSessionDataTask object) , resumable or none-resumable downloading.
| | resumable | none-resumable |
| -------------------------- | --------- | -------------- |
| background supporting | ✅ | ✅ |
| none-background supporting | ✅ | ✅ |
> **Note**:If a none-background supporting downloading is on going then app enters into background, the downloading task will be canceled. And When app enters into foreground again, an ``auto-resume mechanism`` will make the downloading task restart again.
#### Sending download request
Resumable && none-background supporting download reqeust (default configuration):
```objective-c
[[SJNetworkManager sharedManager] sendDownloadRequest:@"wallpaper.jpg"
downloadFilePath:_imageFileLocalPath
progress:^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress)
{
self.progressView.progress = progress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSString *resumableDataPath) {
}];
```
None-resumable && none-background supporting download reqeust:
```objective-c
[[SJNetworkManager sharedManager] sendDownloadRequest:@"half-eatch.jpg"
downloadFilePath:_imageFileLocalPath
resumable:NO
backgroundSupport:NO
progress:^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress)
{
self.progressView.progress = progress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSString *resumableDataPath) {
}];
```
Resumable && background supporting download request:
```objective-c
[[SJNetworkManager sharedManager] sendDownloadRequest:@"universe.jpg"
downloadFilePath:_imageFileLocalPath
resumable:YES
backgroundSupport:YES
progress:^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress)
{
self.progressView.progress = progress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSString *resumableDataPath) {
}];
```
None-resumable && background supporting download request:
```objective-c
[[SJNetworkManager sharedManager] sendDownloadRequest:@"iceberg.jpg"
downloadFilePath:_imageFileLocalPath
resumable:NO
backgroundSupport:YES
progress:^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress)
{
self.progressView.progress = progress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSString *resumableDataPath) {
}];
```
Also supports ignoring base url:
```objective-c
[[SJNetworkManager sharedManager] sendDownloadRequest:@"http://oih3a9o4n.bkt.clouddn.com/wallpaper.jpg"
ignoreBaseUrl:YES
downloadFilePath:_imageFileLocalPath
progress:^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress)
{
self.progressView.progress = progress;
} success:^(id responseObject) {
} failure:^(NSURLSessionTask *task, NSError *error, NSString *resumableDataPath) {
}];
```
#### Suspending download request
Suspending one download current request:
```objective-c
[[SJNetworkManager sharedManager] suspendDownloadRequest:@"universe.jpg"];
```
Suspending one or more than one current download requests:
```objective-c
[[SJNetworkManager sharedManager] suspendDownloadRequests:@[@"universe.jpg",@"wallpaper.jpg"]];
```
Suspending all current download requests:
```objective-c
[[SJNetworkManager sharedManager] suspendAllDownloadRequests];
```
#### Resuming download request
Resuming one download suspended request:
```objective-c
[[SJNetworkManager sharedManager] resumeDownloadReqeust:@"universe.jpg"];
```
Resuming one or more than one download requests:
```objective-c
[[SJNetworkManager sharedManager] resumeDownloadReqeusts:@[@"universe.jpg",@"wallpaper.jpg"]];
```
Resuming all current suspended requests:
```objective-c
[[SJNetworkManager sharedManager] resumeAllDownloadRequests];
```
#### Canceling download request
Canceling one download request:
```objective-c
[[SJNetworkManager sharedManager] cancelDownloadRequest:@"universe.jpg"];
```
Canceling one or more than one current download requests:
```objective-c
[[SJNetworkManager sharedManager] cancelDownloadRequests:@[@"universe.jpg",@"wallpaper.jpg"]];
```
Canceling all current download requests:
```objective-c
[[SJNetworkManager sharedManager] cancelAllDownloadRequests];
```
### Request Management
#### Current request(s) Information
Checking if there is remaining current request(s):
```objective-c
BOOL remaining = [[SJNetworkManager sharedManager] remainingCurrentRequests];
if (remaining) {
NSLog(@"There is remaining request");
}
```
Calculating count of current request(s):
```objective-c
NSUInteger count = [[SJNetworkManager sharedManager] currentRequestCount];
if (count > 0) {
NSLog(@"There is %lu requests",(unsigned long)count);
}
```
Logging all current request(s):
```objective-c
[[SJNetworkManager sharedManager] logAllCurrentRequests];
```
#### Canceling request
Canceling one network request:
```objective-c
[[SJNetworkManager sharedManager] cancelCurrentRequestWithUrl:@"toutiao/index"
method:@"POST"
parameters:@{@"type":@"top",
@"key" :@"0c60"}];
```
Canceling network request(s) with the same url:
```objective-c
[[SJNetworkManager sharedManager] cancelCurrentRequestWithUrl:@"toutiao/index"];
```
Canceling network request(s) with the same urls:
```objective-c
[[SJNetworkManager sharedManager] cancelDownloadRequests:@[@"toutiao/index",@"weixin/query"]];
```
Canceling all current network request(s):
```objective-c
[[SJNetworkManager sharedManager] cancelAllCurrentRequests];
```
### Log Output
If debug mode is set to be yes, detail log will be provided:
```objective-c
[SJNetworkConfig sharedConfig].debugMode = YES;
```
Loading cache before sending network request, but cache is expired:
```objective-c
=========== Load cache info failed, reason:Cache is expired, begin to clear cache...
=========== Load cache failed: Cache info is invalid
=========== Failed to load cache, start to sending network request...
=========== Start requesting...
=========== url:http://v.juhe.cn/toutiao/index
=========== method:GET
=========== parameters:{
app_version = 1.0;
key = 0c60;
platform = iOS;
type = top;
}
=========== Request succeed!
=========== Request url:http://v.juhe.cn/toutiao/index
=========== Response object:{
code = 200,
msg = "",
data = {}
}
=========== Write cache succeed!
=========== cache object: {
code = 200,
msg = "",
data = {}
}
=========== Cache path: /Users/*******/
=========== Available duration: 180 seconds
```
## Acknowledgements
Thanks for these service:
- [JuHe.cn](https://www.juhe.cn/): GET/POST api
- [Uploads.im](http://uploads.im) : Uploading api
- [QINIU](https://portal.qiniu.com/): Multimedia cloud server(for downloading files)
And also thanks for these two excellent framework:
- [AFNetworking](https://github.com/AFNetworking/AFNetworking)
- [YTKNetwork](https://github.com/yuantiku/YTKNetwork)
## Lisence
SJNetwork is released under the [MIT License](https://github.com/knightsj/SJNetwork/blob/master/LICENSE).
================================================
FILE: SJNetwork/SJNetwork.h
================================================
//
// SJNetwork.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/12/27.
// Copyright © 2017年 Shijie. All rights reserved.
//
#ifndef SJNetwork_h
#define SJNetwork_h
#import "SJNetworkManager.h"
#import "SJNetworkConfig.h"
#endif /* SJNetwork_h */
================================================
FILE: SJNetwork/SJNetworkBaseEngine.h
================================================
//
// SJNetworkBaseEngine.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/12/26.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SJNetworkRequestModel.h"
@interface SJNetworkBaseEngine : NSObject
/**
* This method is used to add customed headers, for subclass to override
*/
- (void)addCustomHeaders;
/**
* This method is used to add default parameters with custom parameters, for subclass to override
*
* @param parameters custom parameters
*
*/
- (id)addDefaultParametersWithCustomParameters:(id)parameters;
/**
* This method is used to execute some operation with the request model when the corresponding request succeed, for subclass to override
*
* @param requestModel request model of a network request
*
*/
- (void)requestDidSucceedWithRequestModel:(SJNetworkRequestModel *)requestModel;
@end
================================================
FILE: SJNetwork/SJNetworkBaseEngine.m
================================================
//
// SJNetworkBaseEngine.m
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/12/26.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkBaseEngine.h"
@implementation SJNetworkBaseEngine
- (void)addCustomHeaders{
}
- (id)addDefaultParametersWithCustomParameters:(id)parameters{
return nil;
}
- (void)requestDidSucceedWithRequestModel:(SJNetworkRequestModel *)requestModel{
}
- (void)requestDidFailedWithRequestModel:(SJNetworkRequestModel *)requestModel error:(NSError *)error{
}
@end
================================================
FILE: SJNetwork/SJNetworkCacheInfo.h
================================================
//
// SJNetworkCacheInfo.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/25.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
/* =============================
*
* SJNetworkCacheInfo
*
* SJNetworkCacheInfo is in charge of recording the infomation of cache which is related to a specific network request
*
* =============================
*/
@interface SJNetworkCacheInfo : NSObject<NSSecureCoding>
// Record the creation date of the cache
@property (nonatomic, readwrite, strong) NSDate *creationDate;
// Record the length of the period of validity (unit is second)
@property (nonatomic, readwrite, strong) NSNumber *cacheDuration;
// Record the app version when the cache is created
@property (nonatomic, readwrite, copy) NSString *appVersionStr;
// Record the request identifier of the cache
@property (nonatomic, readwrite, copy) NSString *reqeustIdentifer;
@end
================================================
FILE: SJNetwork/SJNetworkCacheInfo.m
================================================
//
// SJNetworkCacheInfo.m
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/25.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkCacheInfo.h"
@implementation SJNetworkCacheInfo
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.cacheDuration forKey:NSStringFromSelector(@selector(cacheDuration))];
[aCoder encodeObject:self.creationDate forKey:NSStringFromSelector(@selector(creationDate))];
[aCoder encodeObject:self.appVersionStr forKey:NSStringFromSelector(@selector(appVersionStr))];
[aCoder encodeObject:self.reqeustIdentifer forKey:NSStringFromSelector(@selector(reqeustIdentifer))];
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self init];
if (self) {
self.cacheDuration = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(cacheDuration))];
self.creationDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(creationDate))];
self.appVersionStr = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(appVersionStr))];
self.reqeustIdentifer = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(reqeustIdentifer))];
}
return self;
}
- (NSString *)description{
return [NSString stringWithFormat:@"{cacheDuration:%@},{creationDate:%@},{appVersion:%@},{requestIdentifer:%@}",_cacheDuration,_creationDate,_appVersionStr,_reqeustIdentifer];
}
@end
================================================
FILE: SJNetwork/SJNetworkCacheManager.h
================================================
//
// SJNetworkCache.h
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
@class SJNetworkRequestModel;
@class SJNetworkDownloadResumeDataInfo;
// Callback when the cache is cleared
typedef void(^SJClearCacheCompletionBlock)(BOOL isSuccess);
// Callback when the cache is loaded
typedef void(^SJLoadCacheCompletionBlock)(id _Nullable cacheObject);
// Callback when cache array is loaded
typedef void(^SJLoadCacheArrCompletionBlock)(NSArray * _Nullable cacheArr);
// Callback when the size of cache is calculated
typedef void(^SJCalculateSizeCompletionBlock)(NSUInteger fileCount, NSUInteger totalSize, NSString * _Nonnull totalSizeString);
/* =============================
*
* SJNetworkCacheManager
*
* SJNetworkCacheManager is in charge of managing operations of oridinary request cache(and cache info) and resume data (and resume data info)of a certain download request
*
* =============================
*/
@interface SJNetworkCacheManager : NSObject
/**
* SJNetworkCacheManager Singleton
*
* @return SJNetworkCacheManager singleton instance
*/
+ (SJNetworkCacheManager *_Nonnull)sharedManager;
//============================ Write Cache ============================//
/**
* This method is used to write cache(cache data and cache info),
can only be called by SJNetworkManager instance
*
* @param requestModel the model holds the configuration of a specific request
* @param asynchronously if write cache asynchronously
*
*/
- (void)writeCacheWithReqeustModel:(SJNetworkRequestModel * _Nonnull)requestModel asynchronously:(BOOL)asynchronously;
//============================= Load cache =============================//
/**
* This method is used to load cache which is related to a specific url,
no matter what request method is or parameters are
*
*
* @param url the url of related network requests
* @param completionBlock callback
*
*/
- (void)loadCacheWithUrl:(NSString * _Nonnull)url completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock;
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock;
/**
* This method is used to load cache which is related to a specific url,method and parameters
*
* @param url the url of the network request
* @param method the method of the network request
* @param parameters the parameters of the network request
* @param completionBlock callback
*
*/
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters
completionBlock:(SJLoadCacheCompletionBlock _Nullable)completionBlock;
/**
* This method is used to load cache which is related to a identier which is the unique to a network request,
can only be called by SJNetworkManager instance
*
* @param requestIdentifer the unique identier of a specific network request
* @param completionBlock callback
*
*/
- (void)loadCacheWithRequestIdentifer:(NSString * _Nonnull)requestIdentifer completionBlock:(SJLoadCacheCompletionBlock _Nullable)completionBlock;
//============================ calculate cache ============================//
/**
* This method is used to calculate the size of the cache folder (include ordinary request cache and download resume data file and resume data info file)
*
* @param completionBlock finish callback
*
*/
- (void)calculateAllCacheSizecompletionBlock:(SJCalculateSizeCompletionBlock _Nullable)completionBlock;
//============================== clear cache ==============================//
/**
* This method is used to clear all cache which is in the cache folder
*
* @param completionBlock callback
*
*/
- (void)clearAllCacheCompletionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
/**
* This method is used to clear the cache which is related the specific url,
no matter what request method is or parameters are
*
* @param url the url of network request
* @param completionBlock callback
*
*/
- (void)clearCacheWithUrl:(NSString * _Nonnull)url completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
/**
* This method is used to clear cache which is related to a specific url,method and parameters
*
* @param url the url of the network request
* @param method the method of the network request
* @param parameters the parameters of the network request
* @param completionBlock callback
*
*/
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
//============================== Update resume data or resume data info ==============================//
/**
* This method is used to update resume data info after suspending a download request
*
* @param requestModel request model of a network requst
*
*/
- (void)updateResumeDataInfoAfterSuspendWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel;
/**
* This method is used to remove resume data and resume data info files
*
* @param requestModel request model of a network requst
*
*/
- (void)removeResumeDataAndResumeDataInfoFileWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel;
/**
* This method is used to remove download data to target download file path and clear the resume data info file
*
* @param requestModel request model of a network requst
*
*/
- (void)removeCompleteDownloadDataAndClearResumeDataInfoFileWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel;
//============================== Load resume data info ==============================//
/**
* This method is used to load resume data info in a given file path
*
* @param filePath file path
*
*/
- (SJNetworkDownloadResumeDataInfo *_Nullable)loadResumeDataInfo:(NSString *_Nonnull)filePath;
@end
================================================
FILE: SJNetwork/SJNetworkCacheManager.m
================================================
//
// SJNetworkCache.m
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkCacheManager.h"
#import "SJNetworkRequestModel.h"
#import "SJNetworkConfig.h"
#import "SJNetworkUtils.h"
#import "SJNetworkCacheInfo.h"
#import "SJNetworkDownloadResumeDataInfo.h"
#ifndef NSFoundationVersionNumber_iOS_8_0
#define NSFoundationVersionNumber_With_QoS_Available 1140.11
#else
#define NSFoundationVersionNumber_With_QoS_Available NSFoundationVersionNumber_iOS_8_0
#endif
static dispatch_queue_t sj_cache_io_queue() {
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_queue_attr_t attr = DISPATCH_QUEUE_SERIAL;
if (NSFoundationVersionNumber >= NSFoundationVersionNumber_With_QoS_Available) {
attr = dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_BACKGROUND, 0);
}
queue = dispatch_queue_create("com.sj.caching.io", attr);
});
return queue;
}
@implementation SJNetworkCacheManager{
NSFileManager *_fileManager;
NSString *_cacheBasePath;
BOOL _isDebugMode;
}
#pragma mark- ============== Life Cycle Methods ==============
+ (SJNetworkCacheManager *_Nonnull)sharedManager{
static SJNetworkCacheManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[SJNetworkCacheManager alloc] init];
});
return sharedManager;
}
- (instancetype)init{
self = [super init];
if (self) {
_fileManager = [NSFileManager defaultManager];
_cacheBasePath = [SJNetworkUtils createCacheBasePath];
_isDebugMode = [SJNetworkConfig sharedConfig].debugMode;
}
return self;
}
//==================== Write Cache ====================//
#pragma mark- ============== Public Methods ==============
#pragma mark Write Cache
- (void)writeCacheWithReqeustModel:(SJNetworkRequestModel * _Nonnull)requestModel asynchronously:(BOOL)asynchronously{
if (asynchronously) {
dispatch_async(sj_cache_io_queue(), ^{
[self p_wrtieCacheWithRequestModel:requestModel];
});
}else{
[self p_wrtieCacheWithRequestModel:requestModel];
}
}
#pragma mark Load Cache
- (void)loadCacheWithUrl:(NSString * _Nonnull)url completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock{
NSString *partialIdentifier = [SJNetworkUtils generatePartialIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:nil];
[self p_loadCacheWithPartialIdentifier:partialIdentifier completionBlock:completionBlock];
}
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock{
NSString *partialIdentifier = [SJNetworkUtils generatePartialIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:method];
[self p_loadCacheWithPartialIdentifier:partialIdentifier completionBlock:completionBlock];
}
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters
completionBlock:(SJLoadCacheCompletionBlock _Nullable)completionBlock{
NSString *requestIdentifer = [SJNetworkUtils generateRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:method
parameters:parameters];
[self loadCacheWithRequestIdentifer:requestIdentifer completionBlock:^(NSArray * _Nullable cacheArr) {
if (completionBlock) {
completionBlock(cacheArr);
}
}];
}
- (void)loadCacheWithRequestIdentifer:(NSString * _Nonnull)requestIdentifer
completionBlock:(SJLoadCacheCompletionBlock _Nullable)completionBlock{
NSString *cacheDataFilePath = [SJNetworkUtils cacheDataFilePathWithRequestIdentifer:requestIdentifer];
NSString *cacheInfoFilePath = [SJNetworkUtils cacheDataInfoFilePathWithRequestIdentifer:requestIdentifer];
//load cache info
SJNetworkCacheInfo *cacheInfo = [self p_loadCacheInfoWithRequestIdentifier:requestIdentifer];
if (!cacheInfo) {
if (_isDebugMode) {
SJLog(@"=========== Load cache failed: Cache info dose not exists in path:%@",cacheInfoFilePath);
}
[self removeCacheDataFile:cacheDataFilePath cacheInfoFile:cacheInfoFilePath];
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(nil);
}
});
return;
}
BOOL cacheValidation = [self p_checkCacheValidation:cacheInfo];
if (!cacheValidation) {
if (_isDebugMode) {
SJLog(@"=========== Load cache failed: Cache info is invalid");
}
[self removeCacheDataFile:cacheDataFilePath cacheInfoFile:cacheInfoFilePath];
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(nil);
}
});
return;
}
id cacheObject = [self p_loadCacheObjectWithCacheFilePath:cacheDataFilePath];
if (!cacheObject) {
if (_isDebugMode) {
SJLog(@"=========== Load cache failed: Cache data is missing");
}
[self removeCacheDataFile:cacheDataFilePath cacheInfoFile:cacheInfoFilePath];
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(nil);
}
});
return;
}else {
if (_isDebugMode) {
SJLog(@"=========== Load cache succeed: Cache loacation:%@",cacheDataFilePath);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(cacheObject);
}
});
}
}
#pragma mark Calculate Cache
- (void)calculateAllCacheSizecompletionBlock:(SJCalculateSizeCompletionBlock _Nullable)completionBlock{
NSURL *diskCacheURL = [NSURL fileURLWithPath:_cacheBasePath isDirectory:YES];
dispatch_async(sj_cache_io_queue(), ^{
NSUInteger fileCount = 0;
NSUInteger totalSize = 0;
NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
includingPropertiesForKeys:@[NSFileSize]
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:NULL];
for (NSURL *fileURL in fileEnumerator) {
NSNumber *fileSize;
[fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL];
totalSize += fileSize.unsignedIntegerValue;
fileCount += 1;
}
NSString *totalSizeStr = nil;
NSUInteger mb = 1024 *1024;
if (totalSize <mb) {
totalSizeStr = [NSString stringWithFormat:@"%.4f KB",(totalSize * 1.0/1024)];
}else{
totalSizeStr = [NSString stringWithFormat:@"%.4f MB",totalSize * 1.0/(mb)];
}
if (_isDebugMode) {
SJLog(@"=========== Calculate cache size succeed:total fileCount:%ld & totalSize:%@",(unsigned long)fileCount,totalSizeStr);
}
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(fileCount, totalSize, totalSizeStr);
});
}
});
}
#pragma mark Clear Cache
- (void)clearAllCacheCompletionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock{
dispatch_async(sj_cache_io_queue(), ^{
NSError *removeCacheFolderError = nil;
NSError *createCacheFolderError = nil;
[_fileManager removeItemAtPath:_cacheBasePath error:&removeCacheFolderError];
if (!removeCacheFolderError) {
[_fileManager createDirectoryAtPath:_cacheBasePath
withIntermediateDirectories:YES
attributes:nil
error:&createCacheFolderError];
if (!createCacheFolderError) {
dispatch_async(dispatch_get_main_queue(), ^{
SJLog(@"=========== Clearing all cache successfully");
if (completionBlock) {
completionBlock(YES);
return;
}
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
if (_isDebugMode) {
SJLog(@"=========== Clearing cache error: Failed to create cache folder after removing it");
}
if(completionBlock) {
completionBlock(NO);
return;
}
});
}
}else{
dispatch_async(dispatch_get_main_queue(), ^{
if (_isDebugMode) {
SJLog(@"=========== Clearing cache error: Failed to remove cache folder");
}
if (completionBlock) {
completionBlock(NO);
return;
}
});
};
});
}
- (void)clearCacheWithUrl:(NSString * _Nonnull)url completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock{
NSString *partiticalIdentifier = [SJNetworkUtils generatePartialIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:nil];
[self p_clearCacheWithIdentifier:partiticalIdentifier completionBlock:completionBlock];
}
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock{
NSString *partiticalIdentifier = [SJNetworkUtils generatePartialIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:method];
[self p_clearCacheWithIdentifier:partiticalIdentifier completionBlock:completionBlock];
}
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock{
NSString *requestIdentifer = [SJNetworkUtils generateRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url
methodStr:method
parameters:parameters];
[self p_clearCacheWithIdentifier:requestIdentifer completionBlock:completionBlock];
}
#pragma mark Update resume data or resume data info
- (void)updateResumeDataInfoAfterSuspendWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel{
NSData *resumeData = requestModel.task.error.userInfo[NSURLSessionDownloadTaskResumeData];
[resumeData writeToFile:requestModel.resumeDataFilePath options:NSDataWritingAtomic error:nil];
int64_t downloadedByte = requestModel.task.countOfBytesReceived;
int64_t totalByte = requestModel.task.countOfBytesExpectedToReceive;
CGFloat percent = 1.0 *downloadedByte/totalByte;
SJNetworkDownloadResumeDataInfo *dataInfo = [self loadResumeDataInfo:requestModel.resumeDataInfoFilePath];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%lld",downloadedByte];
dataInfo.totalDataLength = [NSString stringWithFormat:@"%lld",totalByte];
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",percent];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:requestModel.resumeDataInfoFilePath];
}
- (void)removeResumeDataAndResumeDataInfoFileWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel{
[_fileManager removeItemAtPath:requestModel.resumeDataFilePath error:nil];
[_fileManager removeItemAtPath:requestModel.resumeDataInfoFilePath error:nil];
}
- (void)removeCompleteDownloadDataAndClearResumeDataInfoFileWithRequestModel:(SJNetworkRequestModel *_Nonnull)requestModel{
NSError *moveFileError = nil;
[_fileManager moveItemAtPath:requestModel.resumeDataFilePath toPath:requestModel.downloadFilePath error:&moveFileError];
if (moveFileError.code == 516) {
[_fileManager removeItemAtPath:requestModel.resumeDataFilePath error:nil];
}
[_fileManager removeItemAtPath:requestModel.resumeDataInfoFilePath error:nil];
}
- (void)removeCacheDataFile:(NSString *)cacheDataFilePath cacheInfoFile:(NSString *)cacheInfoFilePath{
if([_fileManager fileExistsAtPath:cacheDataFilePath]){
[_fileManager removeItemAtPath:cacheDataFilePath error:nil];
}
if([_fileManager fileExistsAtPath:cacheInfoFilePath]){
[_fileManager removeItemAtPath:cacheInfoFilePath error:nil];
}
}
#pragma mark load resume data info
- (SJNetworkDownloadResumeDataInfo *)loadResumeDataInfo:(NSString *)filePath {
SJNetworkDownloadResumeDataInfo *dataInfo = nil;
if ([_fileManager fileExistsAtPath:filePath isDirectory:nil]) {
dataInfo = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
if ([dataInfo isKindOfClass:[SJNetworkDownloadResumeDataInfo class]]) {
return dataInfo;
}else{
return nil;
}
}
return nil;
}
#pragma mark- ============== Private Methods ==============
- (void)p_wrtieCacheWithRequestModel:(SJNetworkRequestModel *)requestModel{
if (requestModel.responseData) {
//path of cache file
[requestModel.responseData writeToFile:requestModel.cacheDataFilePath atomically:YES];
//write cache info data
SJNetworkCacheInfo *cacheInfo = [[SJNetworkCacheInfo alloc] init];
cacheInfo.creationDate = [NSDate date];
cacheInfo.cacheDuration = [NSNumber numberWithInteger:requestModel.cacheDuration];
cacheInfo.appVersionStr = [SJNetworkUtils appVersionStr];
cacheInfo.reqeustIdentifer = requestModel.requestIdentifer;
//write cache info
[NSKeyedArchiver archiveRootObject:cacheInfo toFile:requestModel.cacheDataInfoFilePath];
if (_isDebugMode) {
SJLog(@"=========== Write cache succeed!\n =========== cache object: %@\n =========== Cache path: %@\n =========== Available duration: %@ seconds",requestModel.responseObject,requestModel.cacheDataFilePath,cacheInfo.cacheDuration);
}
}else{
if (_isDebugMode) {
SJLog(@"=========== Write cache failed! reason: There is no responeseData");
}
}
}
- (void)p_loadCacheWithPartialIdentifier:(NSString *)partialIdentifier completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock{
NSDirectoryEnumerator *enumerator = [_fileManager enumeratorAtPath:_cacheBasePath];
NSMutableArray *requestIdentifersArr = [[NSMutableArray alloc] initWithCapacity:2];
for (NSString *fileName in enumerator){
if ([fileName containsString:partialIdentifier]) {
if ([fileName containsString:SJNetworkCacheFileSuffix]) {
NSString *identifier = [fileName substringWithRange:NSMakeRange(0, (fileName.length - SJNetworkCacheFileSuffix.length - 1))];
[requestIdentifersArr addObject:identifier];
}else{
//do not match cache data file
}
}
}
if ([requestIdentifersArr count] > 0) {
NSMutableArray *cacheObjArr = [[NSMutableArray alloc] initWithCapacity:2];
for (NSString* requestIdentifer in requestIdentifersArr) {
[self loadCacheWithRequestIdentifer:requestIdentifer completionBlock:^(id _Nullable cacheObject) {
if (cacheObject) {
[cacheObjArr addObject:cacheObject];
}
}];
}
if (_isDebugMode) {
SJLog(@"=========== Load cache succeed: Found cache corresponding this url");
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock([cacheObjArr copy]);
}
});
}else{
if (_isDebugMode) {
SJLog(@"=========== Load cache failed: There is no any cache corresponding this url");
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(nil);
}
});
}
}
- (BOOL)p_checkCacheValidation:(SJNetworkCacheInfo *)cacheInfo{
if (!cacheInfo || ![cacheInfo isKindOfClass:[SJNetworkCacheInfo class]]) {
return NO;
}
//check duration
NSDate *creationDate = cacheInfo.creationDate;
NSTimeInterval pastDuration = - [creationDate timeIntervalSinceNow];
NSTimeInterval cacheDuration = [cacheInfo.cacheDuration integerValue];
if (cacheDuration <= 0 ) {
if (_isDebugMode) {
SJLog(@"=========== Load cache info failed, reason: Did not set duration time, begin to clear cache...");
}
[self p_clearCacheWithIdentifier:cacheInfo.reqeustIdentifer completionBlock:nil];
return NO;
}
if (pastDuration < 0 || pastDuration > cacheDuration) {
if (_isDebugMode) {
SJLog(@"=========== Load cache info failed, reason:Cache is expired, begin to clear cache...");
}
[self p_clearCacheWithIdentifier:cacheInfo.reqeustIdentifer completionBlock:nil];
return NO;
}
//check app version
NSString *cacheAppVersionStr = cacheInfo.appVersionStr;
NSString *currentAppVersionStr = [SJNetworkUtils appVersionStr];
if ( (!cacheAppVersionStr) && (!currentAppVersionStr)) {
if (_isDebugMode) {
SJLog(@"=========== Load cache info failed, reason: Failed to load app version, begin to clear cache...");
}
[self p_clearCacheWithIdentifier:cacheInfo.reqeustIdentifer completionBlock:nil];
return NO;
}
if (cacheAppVersionStr.length != currentAppVersionStr.length || ![cacheAppVersionStr isEqualToString:currentAppVersionStr]) {
if (_isDebugMode) {
SJLog(@"=========== Load cache info failed, reason: Failed to match app version, begin to clear cache...");
}
[self p_clearCacheWithIdentifier:cacheInfo.reqeustIdentifer completionBlock:nil];
return NO;
}
return YES;
}
- (void)p_clearCacheWithIdentifier:(NSString *)identifier completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock{
NSMutableArray *deleteFileNamesArr = [[NSMutableArray alloc] initWithCapacity:2];
NSDirectoryEnumerator *enumerator = [_fileManager enumeratorAtPath:_cacheBasePath];
for (NSString *fileName in enumerator){
if ([fileName containsString:identifier]) {
NSString *deleteFilePath = [_cacheBasePath stringByAppendingPathComponent:fileName];
[deleteFileNamesArr addObject:deleteFilePath];
}
}
if ([deleteFileNamesArr count] > 0) {
for (NSInteger index = 0; index < deleteFileNamesArr.count; index++) {
dispatch_async(sj_cache_io_queue(), ^{
[_fileManager removeItemAtPath:deleteFileNamesArr[index] error:nil];
if (index == deleteFileNamesArr.count - 1) {
dispatch_async(dispatch_get_main_queue(), ^{
if (_isDebugMode) {
SJLog(@"=========== Clearing cache successfully!");
}
if (completionBlock) {
completionBlock(YES);
return;
}
});
}
});
}
}else{
dispatch_async(dispatch_get_main_queue(), ^{
if (_isDebugMode) {
SJLog(@"=========== Clearing cache error: there is no corresponding cache info");
}
if (completionBlock) {
completionBlock(NO);
return;
}
});
}
}
- (id)p_loadCacheObjectWithCacheFilePath:(NSString *)cacheFilePath{
id cacheObject = nil;
NSError *error = nil;
if ([_fileManager fileExistsAtPath:cacheFilePath isDirectory:nil]) {
NSData *data = [NSData dataWithContentsOfFile:cacheFilePath];
cacheObject = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0 error:&error];
if (cacheObject) {
return cacheObject;
}
}
return cacheObject;
}
- (SJNetworkCacheInfo *)p_loadCacheInfoWithRequestIdentifier:(NSString *)requestIdentifer {
NSString *cacheInfoFilePath = [SJNetworkUtils cacheDataInfoFilePathWithRequestIdentifer:requestIdentifer];
SJNetworkCacheInfo *cacheInfo = nil;
if ([_fileManager fileExistsAtPath:cacheInfoFilePath isDirectory:nil]) {
cacheInfo = [NSKeyedUnarchiver unarchiveObjectWithFile:cacheInfoFilePath];
if ([cacheInfo isKindOfClass:[SJNetworkCacheInfo class]]) {
return cacheInfo;
}else{
return nil;
}
}
return nil;
}
@end
================================================
FILE: SJNetwork/SJNetworkConfig.h
================================================
//
// SJNetworkConfig.h
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
/* =============================
*
* SJNetworkConfig
*
* SJNetworkConfig is in charge of the configuration of all related network requests
*
* =============================
*/
@interface SJNetworkConfig : NSObject
// Base url of requests, default is nil
@property (nonatomic, strong) NSString *_Nullable baseUrl;
// Default parameters, default is nil
@property (nonatomic, strong) NSDictionary * _Nullable defailtParameters;
// Custom headers, default is nil
@property (nonatomic, readonly, strong) NSDictionary * _Nullable customHeaders;
// Request timeout seconds, default is 20 (unit is second)
@property (nonatomic, assign) NSTimeInterval timeoutSeconds;
// If debugMode is set to be YES, then print all detail log
@property (nonatomic, assign) BOOL debugMode;
/**
* SJNetworkConfig Singleton
*
* @return sharedConfig singleton instance
*/
+ (SJNetworkConfig *_Nullable)sharedConfig;
/**
* This method is used to add request headers (key-value pair(or pairs))
*
* @param header custom header to be added into request
*
*/
- (void)addCustomHeader:(NSDictionary *_Nonnull)header;
@end
================================================
FILE: SJNetwork/SJNetworkConfig.m
================================================
//
// SJNetworkConfig.m
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkConfig.h"
@interface SJNetworkConfig()
@property (nonatomic, readwrite, strong) NSDictionary *customHeaders;
@end
@implementation SJNetworkConfig
+ (SJNetworkConfig *)sharedConfig {
static SJNetworkConfig *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
sharedInstance.timeoutSeconds = 20;
});
return sharedInstance;
}
- (void)addCustomHeader:(NSDictionary *)header{
if (![header isKindOfClass:[NSDictionary class]]) {
return;
}
if ([[header allKeys] count] == 0) {
return;
}
if (!_customHeaders) {
_customHeaders = header;
return;
}
//add custom header
NSMutableDictionary *headers_m = [_customHeaders mutableCopy];
[header enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL * _Nonnull stop) {
[headers_m setObject:value forKey:key];
}];
_customHeaders = [headers_m copy];
}
@end
================================================
FILE: SJNetwork/SJNetworkDownloadEngine.h
================================================
//
// SJNetworkDownloadManager.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/25.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SJNetworkBaseEngine.h"
/* =============================
*
* SJNetworkDownloadEngine
*
* SJNetworkDownloadEngine is in charge of sending downloading requests.
*
* =============================
*/
@interface SJNetworkDownloadEngine : SJNetworkBaseEngine
//========================= Request API upload images ==========================//
/**
* This method offers the most number of parameters of a certain download request.
* @note:
* 1. All the other download file API will call this method.
*
* 2. If 'ignoreBaseUrl' is set to be YES, the base url which is holden by
* SJNetworkConfig will be ignored, so the 'url' will be the complete request
* url of this request.(default is set to be YES)
*
* 3. If 'resumable' is set to be YES, incomplete download data will be saved and
* when the same request is sent, the saved data will be used.(default is set to be YES)
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param downloadFilePath target path of download file
* @param resumable consider whether to save or load resumble data
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* This method is used to suspend all current download requests
*/
- (void)suspendAllDownloadRequests;
/**
* This method is used to suspend a download request with given url
*
* @param url download url
*
*/
- (void)suspendDownloadRequest:(NSString * _Nonnull)url;
/**
* This method is used to suspend a download request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)suspendDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to suspend one nor more download requests with given urls array
*
* @param urls download url array
*
*/
- (void)suspendDownloadRequests:(NSArray *_Nonnull)urls;
/**
* This method is used to suspend one nor more download requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)suspendDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to resume all suspended download requests
*/
- (void)resumeAllDownloadRequests;
/**
* This method is used to resume a suspended request with given url
*
* @param url download url
*
*/
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url;
/**
* This method is used to resume a suspended request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to resume one nor more suspended requests with given urls array
*
* @param urls download url array
*
*/
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls;
/**
* This method is used to suspend one nor more suspended requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to cancel all current download requests
*/
- (void)cancelAllDownloadRequests;
/**
* This method is used to cancel a current download request with given url
*
* @param url download url
*
*/
- (void)cancelDownloadRequest:(NSString * _Nonnull)url;
/**
* This method is used to cancel a current download request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)cancelDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to cancel one nor more current download requests with given urls array
*
* @param urls download url array
*
*/
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls;
/**
* This method is used to cancel one nor more current download requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to get incomplete download data ratio of a download request with a given download url
*
* @param url download url
*
* @return incomplete download data ratio
*/
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url;
/**
* This method is used to get incomplete download data ratio of a download request with a given download url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
* @return incomplete download data ratio
*/
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
@end
================================================
FILE: SJNetwork/SJNetworkDownloadEngine.m
================================================
//
// SJNetworkDownloadManager.m
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/25.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkDownloadEngine.h"
#import "SJNetworkDownloadResumeDataInfo.h"
#import "SJNetworkCacheManager.h"
#import "SJNetworkRequestPool.h"
#import "SJNetworkConfig.h"
#import "SJNetworkUtils.h"
#import "SJNetworkProtocol.h"
@interface SJNetworkDownloadEngine()<NSURLSessionDelegate,NSURLSessionDownloadDelegate,SJNetworkProtocol>
@property (nonatomic, strong) NSURLSession *downloadSession;
@property (nonatomic, strong) NSURLSession *backgroundDownloadSession;
@property (nonatomic, strong) SJNetworkCacheManager *cacheManager;
@end
@implementation SJNetworkDownloadEngine
{
NSFileManager *_fileManager;
BOOL _isDebugMode;
}
#pragma mark- ============== Life Cycle Methods ==============
- (instancetype)init{
self = [super init];
if (self) {
//file manager
_fileManager = [NSFileManager defaultManager];
//debug mode
_isDebugMode = [SJNetworkConfig sharedConfig].debugMode;
//cache manager
_cacheManager = [SJNetworkCacheManager sharedManager];
}
return self;
}
- (void)dealloc{
[_backgroundDownloadSession invalidateAndCancel];
[_backgroundDownloadSession resetWithCompletionHandler:^{
}];
[_downloadSession invalidateAndCancel];
[_downloadSession resetWithCompletionHandler:^{
}];
}
#pragma mark- ============== Setter and Getter ==============
- (NSURLSession *)downloadSession
{
static NSURLSession *downloadSession = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = [SJNetworkConfig sharedConfig].timeoutSeconds;
downloadSession = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
});
return downloadSession;
}
- (NSURLSession *)backgroundDownloadSession
{
static NSURLSession *backgroundDownloadSession = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *identifier = @"SJNetworkBackgroundSession";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
sessionConfig.timeoutIntervalForRequest = [SJNetworkConfig sharedConfig].timeoutSeconds;
backgroundDownloadSession = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
});
return backgroundDownloadSession;
}
#pragma mark- ============== Public Methods ==============
#pragma mark ============== Download API ==============
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
//complete request url
NSString *completeUrlStr = nil;
// a unique identifer of a download request
NSString *requestIdentifer = nil;
if (ignoreBaseUrl) {
completeUrlStr = url;
requestIdentifer = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:nil
requestUrlStr:url];
}else{
completeUrlStr = [[SJNetworkConfig sharedConfig].baseUrl stringByAppendingPathComponent:url];
requestIdentifer = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url];
}
//Check if a download task with same download url exists
__block BOOL sameUrlTaskExists = NO;
if ([[SJNetworkRequestPool sharedPool] remainingCurrentRequests]) {
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if ([requestModel.requestUrl isEqualToString:completeUrlStr]) {
sameUrlTaskExists = YES;
SJLog(@"=========== Download request can not be started, since there is a task with the same download url:%@",completeUrlStr);
return;
}
}];
}
if (sameUrlTaskExists) {
return;
}
NSString *downloadTargetFilePath = nil;
BOOL isDirectory;
if(![[NSFileManager defaultManager] fileExistsAtPath:downloadFilePath isDirectory:&isDirectory]) {
isDirectory = NO;
}
// If given downloadFilePath is a directory, then append it with file name to get downloadTargetFilePath(download file path)
if (isDirectory) {
NSString *fileName = [completeUrlStr lastPathComponent];
downloadTargetFilePath = [NSString pathWithComponents:@[downloadFilePath, fileName]];
} else {
downloadTargetFilePath = downloadFilePath;
}
//remove same file in target download path
if ([_fileManager fileExistsAtPath:downloadTargetFilePath]) {
[_fileManager removeItemAtPath:downloadTargetFilePath error:nil];
}
//default method is GET
NSString *methodStr = @"GET";
//create corresponding request model and send request with it
SJNetworkRequestModel *requestModel = [[SJNetworkRequestModel alloc] init];
requestModel.requestUrl = completeUrlStr;
requestModel.method = methodStr;
requestModel.requestIdentifer = requestIdentifer;
requestModel.downloadFilePath = downloadTargetFilePath;
requestModel.resumableDownload = resumable;
requestModel.backgroundDownloadSupport = backgroundSupport;
requestModel.manualOperation = SJDownloadManualOperationStart;
requestModel.downloadSuccessBlock = downloadSuccessBlock;
requestModel.downloadProgressBlock = downloadProgressBlock;
requestModel.downloadFailureBlock = downloadFailureBlock;
NSURLSessionTask *downloadTask = nil;
if (requestModel.backgroundDownloadSupport) {
//downloadTask class : NSURLSessionDownloadTask
downloadTask = [self p_backgroundDownloadTaskWithRequestModel:requestModel];
}else{
//downloadTask class : NSURLSessionDataTask
downloadTask = [self p_noneBackgroundDownloadTaskWithRequestModel:requestModel];
}
//keep task in request model
requestModel.task = downloadTask;
//move this request model into requests set
[[SJNetworkRequestPool sharedPool] addRequestModel:requestModel];
SJLog(@"=========== start downloading:\n =========== url:%@\n =========== downloadPath:%@",completeUrlStr,requestModel.downloadFilePath);
//start request
[downloadTask resume];
}
#pragma mark ============== Suspend API ==============
- (void)suspendAllDownloadRequests{
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
__block BOOL hasDownloadRequests = NO;
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if (requestModel.requestType == SJRequestTypeDownload) {
hasDownloadRequests = YES;
if (requestModel.task) {
if (requestModel.task.state == NSURLSessionTaskStateRunning) {
if (requestModel.backgroundDownloadSupport) {
requestModel.manualOperation = SJDownloadManualOperationSuspend;
NSURLSessionDownloadTask *downloadTask = (NSURLSessionDownloadTask*)requestModel.task;
[downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
}];
}else{
[requestModel.task suspend];
[_cacheManager updateResumeDataInfoAfterSuspendWithRequestModel:requestModel];
SJLog(@"=========== Suspended request:%@",requestModel);
}
}else {
SJLog(@"=========== Request %@ can not be suspended,since it is not running",requestModel);
}
}else {
SJLog(@"=========== There is no donwload task of this request");
}
}
}];
if (!hasDownloadRequests) {
SJLog(@"=========== There is no donwload task to suspend");
}
}
- (void)suspendDownloadRequest:(NSString * _Nonnull)url;{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
//a unique identifer of a download request
NSString *downloadRequestIdentifier = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url];
[self p_suspendDownloadRequestWithDownloadRequestIdentifier:downloadRequestIdentifier];
}
- (void)suspendDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
NSString *baseUrl = nil;
if (!ignoreBaseUrl) {
baseUrl = [SJNetworkConfig sharedConfig].baseUrl;
}
[self p_suspendDownloadRequestWithDownloadRequestIdentifier:[SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:baseUrl requestUrlStr:url]];
}
- (void)suspendDownloadRequests:(NSArray * _Nonnull)urls{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== There is no input donwload urls!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
[urls enumerateObjectsUsingBlock:^(NSString * url, NSUInteger idx, BOOL * _Nonnull stop) {
[self suspendDownloadRequest:url];
}];
}
- (void)suspendDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== There is no input donwload urls!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
[urls enumerateObjectsUsingBlock:^(NSString * url, NSUInteger idx, BOOL * _Nonnull stop) {
[self suspendDownloadRequest:url ignoreBaseUrl:ignoreBaseUrl];
}];
}
#pragma mark ============== Resume API ==============
- (void)resumeAllDownloadRequests{
__block BOOL hasDownloadRequests = NO;
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if (requestModel.requestType == SJRequestTypeDownload) {
hasDownloadRequests = YES;
if (requestModel.task) {
if(requestModel.backgroundDownloadSupport){
NSString *resumeDataFilePath = requestModel.resumeDataFilePath;
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
NSData *resumeData = [NSData dataWithContentsOfFile:resumeDataFilePath];
if (resumeData) {
NSString *oldTaskKey = [NSString stringWithFormat:@"%ld",(unsigned long)requestModel.task.taskIdentifier];
NSURLSessionTask * downloadTask = [self.backgroundDownloadSession downloadTaskWithResumeData:resumeData];
requestModel.task = downloadTask;
//change request model
[[SJNetworkRequestPool sharedPool] changeRequestModel:requestModel forKey:oldTaskKey];
[downloadTask resume];
SJLog(@"=========== Resumed background support download request: %@",requestModel);
}else{
SJLog(@"=========== Can not resume background support download request: %@, since resume data is not available",requestModel);
}
}else{
SJLog(@"=========== Can not resume background support download request: %@, since there is no resume data in path %@",requestModel,resumeDataFilePath);
}
}else{
if (requestModel.task.state == NSURLSessionTaskStateSuspended) {
[requestModel.task resume];
SJLog(@"=========== Resumed request: %@",requestModel);
}else{
SJLog(@"=========== Can not resume request: %@, since it is not suspended",requestModel);
}
}
}else {
SJLog(@"=========== There is no download task of this request");
}
}
}];
if (!hasDownloadRequests) {
SJLog(@"=========== There is no donwload task to resume");
}
}
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
//a unique identifer of a download request
NSString *downloadRequestIdentifier = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url];
[self p_resumeDownloadRequestWithDownloadRequestIdentifier:downloadRequestIdentifier];
}
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
NSString *baseUrl = nil;
if (!ignoreBaseUrl) {
baseUrl = [SJNetworkConfig sharedConfig].baseUrl;
}
//a unique identifer of a download request
NSString *downloadRequestIdentifier = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:baseUrl
requestUrlStr:url];
[self p_resumeDownloadRequestWithDownloadRequestIdentifier:downloadRequestIdentifier];
}
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== There is no input donwload urls!");
}
return;
}
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
[urls enumerateObjectsUsingBlock:^(NSString * url, NSUInteger idx, BOOL * _Nonnull stop) {
[self resumeDownloadReqeust:url];
}];
}
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== There is no input donwload urls!");
}
return;
}
[urls enumerateObjectsUsingBlock:^(NSString * url, NSUInteger idx, BOOL * _Nonnull stop) {
[self resumeDownloadReqeust:url ignoreBaseUrl:ignoreBaseUrl];
}];
}
#pragma mark ============== Cancel API ==============
- (void)cancelAllDownloadRequests{
if(![[SJNetworkRequestPool sharedPool] remainingCurrentRequests]){
return;
}
__block BOOL hasDownloadRequests = NO;
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if (requestModel.requestType == SJRequestTypeDownload) {
hasDownloadRequests = YES;
if (requestModel.task) {
if (requestModel.backgroundDownloadSupport) {
NSURLSessionDownloadTask *downloadTask = (NSURLSessionDownloadTask*)requestModel.task;
requestModel.manualOperation = SJDownloadManualOperationCancel;
[downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
}];
}else{
[requestModel.task cancel];
}
SJLog(@"=========== Canceled request:%@",requestModel);
}else {
SJLog(@"=========== There is no donwload task of this request");
}
}
}];
if (!hasDownloadRequests) {
SJLog(@"=========== There is no donwload task to cancel");
}
}
- (void)cancelDownloadRequest:(NSString * _Nonnull)url{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
[[SJNetworkRequestPool sharedPool] cancelCurrentRequestWithUrl:url];
}
- (void)cancelDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return;
}
NSString *requestUrl = nil;
if (!ignoreBaseUrl) {
requestUrl = [[SJNetworkConfig sharedConfig].baseUrl stringByAppendingPathComponent:url];
}else{
requestUrl = url;
}
[[SJNetworkRequestPool sharedPool] cancelCurrentRequestWithUrl:requestUrl];
}
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url array is empty!");
}
return;
}
[urls enumerateObjectsUsingBlock:^(NSString *url, NSUInteger idx, BOOL * _Nonnull stop) {
[[SJNetworkRequestPool sharedPool] cancelCurrentRequestWithUrl:url];
}];
}
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if ([urls count] == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url array is empty!");
}
return;
}
[urls enumerateObjectsUsingBlock:^(NSString *url, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *requestUrl = nil;
if (!ignoreBaseUrl) {
requestUrl = [[SJNetworkConfig sharedConfig].baseUrl stringByAppendingPathComponent:url];
}else{
requestUrl = url;
}
[[SJNetworkRequestPool sharedPool] cancelCurrentRequestWithUrl:requestUrl];
}];
}
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return 0.0;
}
//a unique identifer of a download request
NSString *downloadRequestIdentifier = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:[SJNetworkConfig sharedConfig].baseUrl
requestUrlStr:url];
return [self p_resumeDataRatioWithRequestIdentifier:downloadRequestIdentifier];
}
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl{
if (url.length == 0) {
if (_isDebugMode) {
SJLog(@"=========== The input url is an empty string!");
}
return 0.0;
}
NSString *baseUrl = nil;
if (!ignoreBaseUrl) {
baseUrl = [SJNetworkConfig sharedConfig].baseUrl;
}
//a unique identifer of a download request
NSString *downloadRequestIdentifier = [SJNetworkUtils generateDownloadRequestIdentiferWithBaseUrlStr:baseUrl requestUrlStr:url];
return [self p_resumeDataRatioWithRequestIdentifier:downloadRequestIdentifier];
}
#pragma mark- ============== Private Methods ==============
- (NSURLSessionTask *)p_backgroundDownloadTaskWithRequestModel:(SJNetworkRequestModel *)requestModel{
//init download request with request url
NSMutableURLRequest *downloadRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestModel.requestUrl]];
//add custom header
[self p_addRequestHeaderInRequest:downloadRequest];
//temp download file
NSString *resumeDataFilePath = requestModel.resumeDataFilePath;
NSString *resumeDataInfoFilePath = requestModel.resumeDataInfoFilePath;
if (![_fileManager fileExistsAtPath:resumeDataInfoFilePath]) {
SJNetworkDownloadResumeDataInfo *dataInfo = [[SJNetworkDownloadResumeDataInfo alloc] init];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:resumeDataInfoFilePath];
}
NSURLSessionDownloadTask *downloadTask = nil;
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
NSData *resumeData = [NSData dataWithContentsOfFile:resumeDataFilePath];
if (resumeData) {
if (requestModel.resumableDownload) {
downloadTask = [self.backgroundDownloadSession downloadTaskWithResumeData:resumeData];
}else{
[_fileManager removeItemAtPath:resumeDataFilePath error:nil];
downloadTask = [self.backgroundDownloadSession downloadTaskWithRequest:downloadRequest];
}
}else{
[_fileManager removeItemAtPath:resumeDataFilePath error:nil];
downloadTask = [self.backgroundDownloadSession downloadTaskWithRequest:downloadRequest];
}
}else{
downloadTask = [self.backgroundDownloadSession downloadTaskWithRequest:downloadRequest];
}
return downloadTask;
}
- (NSURLSessionTask *)p_noneBackgroundDownloadTaskWithRequestModel:(SJNetworkRequestModel *)requestModel{
//init download request with request url
NSMutableURLRequest *downloadRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestModel.requestUrl]];
//add custom header
[self p_addRequestHeaderInRequest:downloadRequest];
//temp download file
NSString *resumDataFilePath = requestModel.resumeDataFilePath;
NSString *resumeDataInfoFilePath = requestModel.resumeDataInfoFilePath;
//create steam
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:resumDataFilePath append:YES];
requestModel.stream = stream;
if (requestModel.resumableDownload) {
if ([_fileManager fileExistsAtPath:resumeDataInfoFilePath] ) {
//load resume data info
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:resumeDataInfoFilePath];
//check if resume data info exsists
if (dataInfo) {
NSInteger resumeDataLength = [dataInfo.resumeDataLength integerValue];
if (resumeDataLength > 0) {
NSString *range = [NSString stringWithFormat:@"bytes=%zd-", resumeDataLength];
[downloadRequest setValue:range forHTTPHeaderField:@"Range"];
}
}else{
//if resume data info was not available and the corresponding data exists, then delete the corresponding data
if ([_fileManager fileExistsAtPath:resumDataFilePath]) {
[_fileManager removeItemAtPath:resumeDataInfoFilePath error:nil];
}
}
}else {
//if this is a not a resumable download request and there is no resume data info, then create one
SJNetworkDownloadResumeDataInfo *dataInfo = [[SJNetworkDownloadResumeDataInfo alloc] init];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:resumeDataInfoFilePath];
}
}
NSURLSessionDataTask *downloadTask = [self.downloadSession dataTaskWithRequest:downloadRequest];
return downloadTask;
}
- (void)p_addRequestHeaderInRequest:(NSMutableURLRequest *)request{
NSDictionary *customHeaders = [SJNetworkConfig sharedConfig].customHeaders;
if ([customHeaders allKeys] > 0) {
NSArray *allKeys = [customHeaders allKeys];
if ([allKeys count] >0) {
[customHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL * _Nonnull stop) {
[request setValue:value forHTTPHeaderField:key];
if (_isDebugMode) {
SJLog(@"=========== added header:key:%@ value:%@",key,value);
}
}];
}
}
}
- (void)p_suspendDownloadRequestWithDownloadRequestIdentifier:(NSString *)downloadRequestIdentifier{
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if ([requestModel.requestIdentifer isEqualToString:downloadRequestIdentifier]) {
if (requestModel.task) {
if (requestModel.task.state == NSURLSessionTaskStateRunning) {
if (requestModel.backgroundDownloadSupport) {
requestModel.manualOperation = SJDownloadManualOperationSuspend;
NSURLSessionDownloadTask *downloadTask = (NSURLSessionDownloadTask*)requestModel.task;
[downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
}];
}else{
[requestModel.task suspend];
[_cacheManager updateResumeDataInfoAfterSuspendWithRequestModel:requestModel];
SJLog(@"=========== Suspended request:%@",requestModel);
}
}else {
SJLog(@"=========== Request %@ can not be suspended,since it is not running",requestModel);
}
}else {
SJLog(@"=========== There is no donwload task of this request");
}
}
}];
}
- (void)p_resumeDownloadRequestWithDownloadRequestIdentifier:(NSString *)downloadRequestIdentifier{
[[SJNetworkRequestPool sharedPool].currentRequestModels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SJNetworkRequestModel * _Nonnull requestModel, BOOL * _Nonnull stop) {
if ([requestModel.requestIdentifer isEqualToString:downloadRequestIdentifier]) {
if (requestModel.task) {
if (requestModel.backgroundDownloadSupport) {
if (requestModel.manualOperation == SJDownloadManualOperationSuspend) {
NSString *resumeDataFilePath = requestModel.resumeDataFilePath;
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
NSData *resumeData = [NSData dataWithContentsOfFile:resumeDataFilePath];
if (resumeData) {
NSString *oldTaskKey = [NSString stringWithFormat:@"%ld",(unsigned long)requestModel.task.taskIdentifier];
NSURLSessionTask * downloadTask = [self.backgroundDownloadSession downloadTaskWithResumeData:resumeData];
requestModel.manualOperation = SJDownloadManualOperationResume;
requestModel.task = downloadTask;
[[SJNetworkRequestPool sharedPool] changeRequestModel:requestModel forKey:oldTaskKey];
[downloadTask resume];
SJLog(@"=========== Resumed background support download request: %@",requestModel);
}else{
SJLog(@"=========== Can not resume background support download request: %@, since resume data is not available",requestModel);
}
}else{
SJLog(@"=========== Can not resume background support download request: %@, since there is no resume data in path %@",requestModel,resumeDataFilePath);
}
}else{
SJLog(@"=========== Can not resume background support download request: %@, since it is not suspended(canceled) by user",requestModel);
}
}else{
if (requestModel.task.state == NSURLSessionTaskStateSuspended) {
[requestModel.task resume];
SJLog(@"=========== Resumed request: %@",requestModel);
}else{
SJLog(@"=========== Can not resume request: %@, since it is not suspended",requestModel);
}
}
}else {
SJLog(@"=========== There is no download task of this request");
}
}
}];
}
- (CGFloat)p_resumeDataRatioWithRequestIdentifier:(NSString *)requestIdentifier{
NSString *resumeDataInfoFilePath = [SJNetworkUtils resumeDataInfoFilePathWithRequestIdentifer:requestIdentifier];
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:resumeDataInfoFilePath];
if (dataInfo) {
return [dataInfo.resumeDataRatio floatValue];
}else{
return 0.00;
}
}
#pragma mark- ============== SJNetworkProtocol ==============
- (void)handleRequesFinished:(SJNetworkRequestModel *)requestModel{
//clear all blocks
[requestModel clearAllBlocks];
//remove this requst model from request queue
[[SJNetworkRequestPool sharedPool] removeRequestModel:requestModel];
}
#pragma mark - ============== NSURLSessionTaskDelegate ==============
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error{
if (_isDebugMode) {
SJLog(@"=========== Download request did complete of task:%@",task);
}
SJNetworkRequestModel * requestModel = [[SJNetworkRequestPool sharedPool].currentRequestModels objectForKey:[NSString stringWithFormat:@"%ld",(unsigned long)task.taskIdentifier]];
if (requestModel) {
if (requestModel.backgroundDownloadSupport) {
if (error) {
//cancel request
if (error.code == -999) {
[requestModel.task suspend];
NSData *resumeData = requestModel.task.error.userInfo[NSURLSessionDownloadTaskResumeData];
NSError *moveDownloadFileError = nil;
if (requestModel.resumableDownload) {
[resumeData writeToFile:requestModel.resumeDataFilePath options:NSDataWritingAtomic error:&moveDownloadFileError];
}else{
if (requestModel.manualOperation == SJDownloadManualOperationSuspend){
[resumeData writeToFile:requestModel.resumeDataFilePath options:NSDataWritingAtomic error:&moveDownloadFileError];
}else{
if (_isDebugMode) {
SJLog(@"=========== Because this is not resumable downloading:\n remove resume data in path:%@ \n and resume data info in path:%@",requestModel.resumeDataFilePath,requestModel.resumeDataInfoFilePath);
}
[_cacheManager removeResumeDataAndResumeDataInfoFileWithRequestModel:requestModel];
}
}
if (requestModel.manualOperation == SJDownloadManualOperationSuspend) {
SJLog(@"=========== Suspended background support download request:%@",requestModel);
}else{
SJLog(@"=========== Canceled background support download request:%@",requestModel);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, error,requestModel.resumeDataFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}else{
SJLog(@"=========== Background support download failed, download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, error,requestModel.resumeDataFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}else{
SJLog(@"=========== Download succeed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{\
if (requestModel.downloadSuccessBlock) {
requestModel.downloadSuccessBlock(requestModel.downloadFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}else {
if (error) {
if (error.code == -997) {
// The eror code equals to -997 means this app enters into background and then lost connect.
// We offer an 'auto start request mechanism' to cope with this situation
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:requestModel.resumeDataInfoFilePath];
NSDictionary *attributeDict = [_fileManager attributesOfItemAtPath:requestModel.resumeDataFilePath error:nil];
NSInteger resumeDataLength = [attributeDict[NSFileSize] integerValue];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%ld",(long)resumeDataLength];
//ratio
CGFloat ratio = 1.0 * ([dataInfo.resumeDataLength integerValue])/([dataInfo.totalDataLength integerValue]);
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",ratio];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:requestModel.resumeDataInfoFilePath];
[requestModel.stream close];
requestModel.stream = nil;
//lost connection background and the task is canceled
NSString *oldTaskKey = [NSString stringWithFormat:@"%ld",(unsigned long)requestModel.task.taskIdentifier];
//init download request with request url
NSURLSessionTask * downloadTask = [self p_noneBackgroundDownloadTaskWithRequestModel:requestModel];
requestModel.task = downloadTask;
//change request model
[[SJNetworkRequestPool sharedPool] changeRequestModel:requestModel forKey:oldTaskKey];
[requestModel.task resume];
}else{
if (requestModel.resumableDownload) {
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:requestModel.resumeDataInfoFilePath];
NSDictionary *attributeDict = [_fileManager attributesOfItemAtPath:requestModel.resumeDataFilePath error:nil];
NSInteger resumeDataLength = [attributeDict[NSFileSize] integerValue];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%ld",(long)resumeDataLength];
//ratio
CGFloat ratio = 1.0 * ([dataInfo.resumeDataLength integerValue])/([dataInfo.totalDataLength integerValue]);
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",ratio];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:requestModel.resumeDataInfoFilePath];
if (_isDebugMode) {
SJLog(@"=========== Keep resume data in path:%@ \n and save resume data info in path:%@, since this is a resumable donwloading",requestModel.resumeDataFilePath,requestModel.resumeDataInfoFilePath);
}
}else {
if (_isDebugMode) {
SJLog(@"=========== Remove resume data in path:%@ \n and resume data info in path:%@, since this is not a resumable donwloading",requestModel.resumeDataFilePath,requestModel.resumeDataInfoFilePath);
}
[_cacheManager removeResumeDataAndResumeDataInfoFileWithRequestModel:requestModel];
}
[requestModel.stream close];
requestModel.stream = nil;
SJLog(@"=========== Download failed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, error,requestModel.resumeDataFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}else {
//download succeed
[_cacheManager removeCompleteDownloadDataAndClearResumeDataInfoFileWithRequestModel:requestModel];
[requestModel.stream close];
requestModel.stream = nil;
SJLog(@"=========== Download succeed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadSuccessBlock) {
requestModel.downloadSuccessBlock(requestModel.downloadFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}
}
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSHTTPURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
if (_isDebugMode) {
SJLog(@"=========== Did received response:%@ \n of task:%@",response,dataTask);
}
SJNetworkRequestModel * requestModel = [[SJNetworkRequestPool sharedPool].currentRequestModels objectForKey:[NSString stringWithFormat:@"%ld",(unsigned long)dataTask.taskIdentifier]];
if (requestModel) {
NSInteger statusCode = 0;
if ([dataTask.response isKindOfClass:[NSHTTPURLResponse class]]) {
statusCode = [(NSHTTPURLResponse*)dataTask.response statusCode];
}
NSString *resumeDataInfoFilePath = requestModel.resumeDataInfoFilePath;
NSString *resumeDataFilePath= requestModel.resumeDataFilePath;
if (statusCode > 400) {
NSError *error = [NSError errorWithDomain:@"request error" code:statusCode userInfo:nil];
[_fileManager removeItemAtPath:resumeDataInfoFilePath error:nil];
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
[_fileManager removeItemAtPath:resumeDataFilePath error:nil];
}
SJLog(@"=========== Download failed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, error,nil);
}
[self handleRequesFinished:requestModel];
});
return;
}
//no error, open stream
[requestModel.stream open];
//load resume data info
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:requestModel.resumeDataInfoFilePath];
if (!dataInfo) {
dataInfo = [[SJNetworkDownloadResumeDataInfo alloc] init];
}
//resume data file length
NSDictionary *attributeDict = [_fileManager attributesOfItemAtPath:resumeDataFilePath error:nil];
NSInteger resumeDataLength = [attributeDict[NSFileSize] integerValue];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%ld",(long)resumeDataLength];
//total data file length
NSInteger totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + [dataInfo.resumeDataLength integerValue];
dataInfo.totalDataLength = [NSString stringWithFormat:@"%ld",(long)totalLength];
requestModel.totalLength = totalLength;
//ratio
CGFloat ratio = 1.0 * ([dataInfo.resumeDataLength integerValue])/([dataInfo.totalDataLength integerValue]);
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",ratio];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:requestModel.resumeDataInfoFilePath];
completionHandler(NSURLSessionResponseAllow);
}
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
SJNetworkRequestModel * requestModel = [[SJNetworkRequestPool sharedPool].currentRequestModels objectForKey:[NSString stringWithFormat:@"%ld",(unsigned long)dataTask.taskIdentifier]];
if (requestModel) {
//write data in stream
[requestModel.stream write:data.bytes maxLength:data.length];
//update resume data info
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo: requestModel.resumeDataInfoFilePath];
NSDictionary *attributeDict = [_fileManager attributesOfItemAtPath:requestModel.resumeDataFilePath error:nil];
NSInteger resumeDataLength = [attributeDict[NSFileSize] integerValue];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%ld",(long)resumeDataLength];
CGFloat ratio = 1.0 * ([dataInfo.resumeDataLength integerValue])/([dataInfo.totalDataLength integerValue]);
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",ratio];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:requestModel.resumeDataInfoFilePath];
if (_isDebugMode) {
SJLog(@"=========== Download progress:%@ of task:%@",dataInfo.resumeDataRatio,requestModel.task);
}
if (requestModel.downloadProgressBlock) {
requestModel.downloadProgressBlock([dataInfo.resumeDataLength integerValue] ,requestModel.totalLength,ratio);
}
}
}
#pragma mark - ============== NSURLSessionDownloadDelegate ==============
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
SJNetworkRequestModel * requestModel = [[SJNetworkRequestPool sharedPool].currentRequestModels objectForKey:[NSString stringWithFormat:@"%ld",(unsigned long)downloadTask.taskIdentifier]];
if (requestModel) {
NSInteger statusCode = 0;
if ([downloadTask.response isKindOfClass:[NSHTTPURLResponse class]]) {
statusCode = [(NSHTTPURLResponse*)downloadTask.response statusCode];
}
NSString *resumeDataInfoFilePath = requestModel.resumeDataInfoFilePath;
NSString *resumeDataFilePath= requestModel.resumeDataFilePath;
if (statusCode > 400) {
NSError *error = nil;
if (statusCode == 416) {
error = [NSError errorWithDomain:@"range error" code:statusCode userInfo:nil];
}
[_fileManager removeItemAtPath:resumeDataInfoFilePath error:nil];
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
[_fileManager removeItemAtPath:resumeDataFilePath error:nil];
}
SJLog(@"=========== Download failed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, error,nil);
}
[self handleRequesFinished:requestModel];
});
}else{
NSData *tmpDownloadFileData = [NSData dataWithContentsOfURL:location];
NSUInteger downloadDataLength = tmpDownloadFileData.length;
//download succeed
NSError *moveDownloadFileError = nil;
//move temp download data to target file path
[_fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:requestModel.downloadFilePath] error:&moveDownloadFileError];
//remove data info file path
[_fileManager removeItemAtPath:resumeDataInfoFilePath error:nil];
if ([_fileManager fileExistsAtPath:resumeDataFilePath]) {
[_fileManager removeItemAtPath:resumeDataFilePath error:nil];
}
if (moveDownloadFileError && moveDownloadFileError.code != 516) {
SJLog(@"=========== Download failed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadFailureBlock) {
requestModel.downloadFailureBlock(requestModel.task, moveDownloadFileError,nil);
}
[self handleRequesFinished:requestModel];
});
}else {
if (requestModel.downloadProgressBlock) {
requestModel.downloadProgressBlock(downloadDataLength, downloadDataLength, 1);
}
if (moveDownloadFileError.code == 516) {
[_fileManager removeItemAtPath:location.absoluteString error:nil];
}
//succeed block
SJLog(@"=========== Download succeed,download file path:%@",requestModel.downloadFilePath);
dispatch_async(dispatch_get_main_queue(), ^{
if (requestModel.downloadSuccessBlock) {
requestModel.downloadSuccessBlock(requestModel.downloadFilePath);
}
[self handleRequesFinished:requestModel];
});
}
}
}
}
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
SJNetworkRequestModel * requestModel = [[SJNetworkRequestPool sharedPool].currentRequestModels objectForKey:[NSString stringWithFormat:@"%ld",(unsigned long)downloadTask.taskIdentifier]];
if (requestModel) {
if (!requestModel.totalLength) {
requestModel.totalLength = (NSInteger)totalBytesExpectedToWrite;
}
CGFloat ratio = 1.0 *totalBytesWritten/requestModel.totalLength;
NSString *resumeDataInfoFilePath = requestModel.resumeDataInfoFilePath;
SJNetworkDownloadResumeDataInfo *dataInfo = [_cacheManager loadResumeDataInfo:resumeDataInfoFilePath];
dataInfo.resumeDataLength = [NSString stringWithFormat:@"%lld",totalBytesWritten];
dataInfo.totalDataLength = [NSString stringWithFormat:@"%ld",(long)requestModel.totalLength];
dataInfo.resumeDataRatio = [NSString stringWithFormat:@"%.2f",ratio];
[NSKeyedArchiver archiveRootObject:dataInfo toFile:resumeDataInfoFilePath];
if (_isDebugMode) {
SJLog(@"=========== Download progress:%@ of task:%@",dataInfo.resumeDataRatio,requestModel.task);
}
if (requestModel.downloadProgressBlock) {
requestModel.downloadProgressBlock((NSInteger)bytesWritten ,requestModel.totalLength,ratio);
}
}
}
@end
================================================
FILE: SJNetwork/SJNetworkDownloadResumeDataInfo.h
================================================
//
// SJNetworkResumeDataInfo.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/28.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
/* =============================
*
* SJNetworkDownloadResumeDataInfo
*
* SJNetworkDownloadResumeDataInfo is in charge of recording the infomation of resume data of the corresponding download request
*
* =============================
*/
@interface SJNetworkDownloadResumeDataInfo : NSObject<NSSecureCoding>
// Record the resume data length
@property (nonatomic, readwrite, copy) NSString *resumeDataLength;
// Record total length of the download data
@property (nonatomic, readwrite, copy) NSString *totalDataLength;
// Record the ratio of resume data length and total length of download data (resumeDataLength/dataTotalLength)
@property (nonatomic, readwrite, copy) NSString *resumeDataRatio;
@end
================================================
FILE: SJNetwork/SJNetworkDownloadResumeDataInfo.m
================================================
//
// SJNetworkResumeDataInfo.m
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/11/28.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkDownloadResumeDataInfo.h"
@implementation SJNetworkDownloadResumeDataInfo
#pragma mark- ============== Life Cycle Methods ==============
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self init];
if (self) {
self.resumeDataRatio = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(resumeDataRatio))];
self.resumeDataLength = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(resumeDataLength))];
self.totalDataLength = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(totalDataLength))];
}
return self;
}
#pragma mark- ============== Override Methods ==============
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.resumeDataLength forKey:NSStringFromSelector(@selector(resumeDataLength))];
[aCoder encodeObject:self.totalDataLength forKey:NSStringFromSelector(@selector(totalDataLength))];
[aCoder encodeObject:self.resumeDataRatio forKey:NSStringFromSelector(@selector(resumeDataRatio))];
}
- (NSString *)description{
return [NSString stringWithFormat:@"<%@: %p>:{resume data length:%@}, {total data length:%@},{ratio:%@}",NSStringFromClass([self class]), self,_resumeDataLength, _totalDataLength, _resumeDataRatio];
}
@end
================================================
FILE: SJNetwork/SJNetworkHeader.h
================================================
//
// SJNetworkHeader.h
// SJNetworkingDemo
//
// Created by Sun Shijie on 2017/12/26.
// Copyright © 2017年 Shijie. All rights reserved.
//
#ifndef SJNetworkHeader_h
#define SJNetworkHeader_h
#import <AFNetworking/AFNetworking.h>
//Log used to debug
#ifdef DEBUG
#define SJLog(...) NSLog(@"%s line number:%d \n %@\n\n",__func__,__LINE__,[NSString stringWithFormat:__VA_ARGS__])
#else
#define SJLog(...)
#endif
//============== Callbacks: Only for ordinary request ==================//
typedef void(^SJSuccessBlock)(id responseObject);
typedef void(^SJFailureBlock)(NSURLSessionTask *task, NSError *error, NSInteger statusCode);
//============== Callbacks: Only for upload request ==================//
typedef void(^SJUploadSuccessBlock)(id responseObject);
typedef void(^SJUploadProgressBlock)(NSProgress *uploadProgress);
typedef void(^SJUploadFailureBlock)(NSURLSessionTask *task, NSError *error, NSInteger statusCode, NSArray<UIImage *>*uploadFailedImages);
//============== Callbacks: Only for download request ==================//
typedef void(^SJDownloadSuccessBlock)(id responseObject);
typedef void(^SJDownloadProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress);
typedef void(^SJDownloadFailureBlock)(NSURLSessionTask *task, NSError *error, NSString* resumableDataPath);
/**
* HTTP Request method
*/
typedef NS_ENUM(NSInteger, SJRequestMethod) {
SJRequestMethodGET = 60000,
SJRequestMethodPOST,
SJRequestMethodPUT,
SJRequestMethodDELETE,
};
/**
* Request type
*/
typedef NS_ENUM(NSInteger, SJRequestType) {
SJRequestTypeOrdinary = 70000,
SJRequestTypeUpload,
SJRequestTypeDownload
};
/**
* Manual operation by user (start,suspend,resume,cancel)
*/
typedef NS_ENUM(NSInteger, SJDownloadManualOperation) {
SJDownloadManualOperationStart = 80000,
SJDownloadManualOperationSuspend,
SJDownloadManualOperationResume,
SJDownloadManualOperationCancel,
};
#endif /* SJNetworkHeader_h */
================================================
FILE: SJNetwork/SJNetworkManager.h
================================================
//
// SJNetworkManager.h
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "SJNetworkRequestModel.h"
#import "SJNetworkCacheManager.h"
/* =============================
*
* SJNetworkManager
*
* SJNetworkManager is in charge of managing operations of network request
*
* =============================
*/
@interface SJNetworkManager : NSObject
/**
* SJNetworkManager Singleton
*
* @return SJNetworkManager singleton instance
*/
+ (SJNetworkManager *_Nullable)sharedManager;
/**
* can not use new method
*/
+ (instancetype _Nullable)new NS_UNAVAILABLE;
/**
* This method is used to add custom header
*
* @param header custom header added by user
*
*/
- (void)addCustomHeader:(NSDictionary *_Nonnull)header;
/**
* This method is used to return custom header
*
* @return custom header
*/
- (NSDictionary *_Nullable)customHeaders;
#pragma mark- Request API using GET method
/**
* This method is used to send GET request,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendGetRequest:(NSString * _Nonnull)url
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send GET request,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send GET request,
consider whether to load cache but not consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send GET request,
consider whether to write cache but not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send GET request,
consider whether to load cache and consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
#pragma mark- Request API using POST method
/**
* This method is used to send POST request,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache but not consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to write cache but not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache and consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
#pragma mark- Request API using PUT method
/**
* This method is used to send PUT request,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache but not consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to write cache but not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache and consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
#pragma mark- Request API using DELETE method
/**
* This method is used to send DELETE request,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache but not consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to write cache but not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send POST request,
consider whether to load cache and consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
#pragma mark- Request API using specific parameters
/**
* These methods are used to send request with specific parameters:
1. if the parameters object is nil,then send GET request
2. if the parameters object is not nil,then send POST request
*/
/**
* This method is used to send request with specific parameters,
not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific parameters,
not consider whether to write cache but consider whether to load cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific parameters,
not consider whether to load cache but consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific parameters,
consider whether to load cache and consider whether to write cache
*
* @param url request url
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
//================== Request API using specific request method ==================//
/**
* This method is used to send request with specific method(GET,POST,PUT,DELETE),
* not consider whether to write cache & not consider whether to load cache
*
* @param url request url
* @param method request method
* @param parameters parameters
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific method(GET,POST,PUT,DELETE),
* not consider whether to write cache but consider whether to load cache
*
* @param url request url
* @param method request method
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific method(GET,POST,PUT,DELETE),
* not consider whether to load cache but consider whether to write cache
*
* @param url request url
* @param method request method
* @param parameters parameters
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
/**
* This method is used to send request with specific method(GET,POST,PUT,DELETE),
* consider whether to load cache but consider whether to write cache
*
* @param url request url
* @param method request method
* @param parameters parameters
* @param loadCache consider whether to load cache
* @param cacheDuration consider whether to write cache
* @param successBlock success callback
* @param failureBlock failure callback
*
*/
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock;
#pragma mark- Request API upload images
/**
* This method is used to upload image
*
* @param url request url
* @param parameters parameters
* @param image UIImage object
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock uploadSuccess allback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload image
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param parameters parameters
* @param image UIImage object
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload images(or only one image)
*
* @param url request url
* @param parameters parameters
* @param images UIImage object array
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload images(or only one image)
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param parameters parameters
* @param images UIImage object array
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload image
*
* @param url request url
* @param parameters parameters
* @param image UIImage object
* @param compressRatio compress ratio of images
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload image
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param parameters parameters
* @param image UIImage object
* @param compressRatio compress ratio of images
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
* This method is used to upload images(or only one image)
*
* @param url request url
* @param parameters parameters
* @param images UIImage object array
* @param compressRatio compress ratio of images
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
/**
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param parameters parameters
* @param images UIImage object array
* @param compressRatio compress ratio of images
* @param name file name
* @param mimeType file type
* @param uploadProgressBlock upload progress callback
* @param uploadSuccessBlock upload success callback
* @param uploadFailureBlock upload failure callback
*
*/
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock;
#pragma mark- Request API download files
/**
* These methods are used to download file
*
* @param url request url
* @param downloadFilePath target path of download file
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param downloadFilePath target path of download file
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param downloadFilePath target path of download file
* @param resumable consider whether to save or load resumble data
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param downloadFilePath target path of download file
* @param resumable consider whether to save or load resumble data
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param downloadFilePath target path of download file
* @param backgroundSupport consider whether to support background downlaod
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param downloadFilePath target path of download file
* @param backgroundSupport consider whether to support background downlaod
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param downloadFilePath target path of download file
* @param resumable consider whether to save or load resumble data
* @param backgroundSupport consider whether to support background downlaod
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
/**
* These methods are used to download file
*
* @param url request url
* @param ignoreBaseUrl consider whether to ignore configured base url
* @param downloadFilePath target path of download file
* @param resumable consider whether to save or load resumble data
* @param backgroundSupport consider whether to support background downlaod
* @param downloadProgressBlock download progress callback
* @param downloadSuccessBlock download success callback
* @param downloadFailureBlock download failure callback
*
*/
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock;
//=============================== Suspend download requests ==================================//
/**
* This method is used to suspend all current download requests
*/
- (void)suspendAllDownloadRequests;
/**
* This method is used to suspend a download request with given url
*
* @param url download url
*
*/
- (void)suspendDownloadRequest:(NSString * _Nonnull)url;
/**
* This method is used to suspend a download request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)suspendDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to suspend one nor more download requests with given urls array
*
* @param urls download url array
*
*/
- (void)suspendDownloadRequests:(NSArray *_Nonnull)urls;
/**
* This method is used to suspend one nor more download requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)suspendDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
//=============================== Resume download requests ==================================//
/**
* This method is used to resume all suspended download requests
*/
- (void)resumeAllDownloadRequests;
/**
* This method is used to resume a suspended request with given url
*
* @param url download url
*
*/
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url;
/**
* This method is used to resume a suspended request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)resumeDownloadReqeust:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to resume one nor more suspended requests with given urls array
*
* @param urls download url array
*
*/
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls;
/**
* This method is used to suspend one nor more suspended requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)resumeDownloadReqeusts:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
//=============================== Cancel download requests ==================================//
/**
* This method is used to cancel all current download requests
*/
- (void)cancelAllDownloadRequests;
/**
* This method is used to cancel a current download request with given url
*
* @param url download url
*
*/
- (void)cancelDownloadRequest:(NSString * _Nonnull)url;
/**
* This method is used to cancel a current download request with given url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)cancelDownloadRequest:(NSString * _Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to cancel one nor more current download requests with given urls array
*
* @param urls download url array
*
*/
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls;
/**
* This method is used to cancel one nor more current download requests with given urls which contain the baseUrl or not
*
* @param urls download url array
* @param ignoreBaseUrl ignore baseUrl or not
*
*/
- (void)cancelDownloadRequests:(NSArray *_Nonnull)urls ignoreBaseUrl:(BOOL)ignoreBaseUrl;
/**
* This method is used to get incomplete download data ratio of a download request with a given download url
*
* @param url download url
*
* @return incomplete download data ratio
*/
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url;
/**
* This method is used to get incomplete download data ratio of a download request with a given download url which contains the baseUrl or not
*
* @param url download url
* @param ignoreBaseUrl ignore baseUrl or not
*
* @return incomplete download data ratio
*/
- (CGFloat)resumeDataRatioOfRequest:(NSString *_Nonnull)url ignoreBaseUrl:(BOOL)ignoreBaseUrl;
#pragma mark- Cancel requests
/**
* This method is used to cancel all current requests
*/
- (void)cancelAllCurrentRequests;
/**
* This method is used to cancel all current requests corresponding a reqeust url,
no matter what the method is and parameters are
*
* @param url request url
*
*/
- (void)cancelCurrentRequestWithUrl:(NSString * _Nonnull)url;
/**
* This method is used to cancel all current requests corresponding a specific reqeust url, method and parameters
*
* @param url request url
* @param method request method
* @param parameters parameters
*
*/
- (void)cancelCurrentRequestWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters;
#pragma mark- Cache operations
//=============================== Load cache ==================================//
/**
* This method is used to load cache which is related to a specific url,
no matter what request method is or parameters are
*
*
* @param url the url of related network requests
* @param completionBlock callback
*
*/
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock;
/**
* This method is used to load cache which is related to a specific url,method and parameters
*
* @param url the url of the network request
* @param method the method of the network request
* @param parameters the parameters of the network request
* @param completionBlock callback
*
*/
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nullable)parameters
completionBlock:(SJLoadCacheCompletionBlock _Nullable)completionBlock;
//=============================== calculate cache ===========================//
/**
* This method is used to calculate the size of the cache folder
*
* @param completionBlock callback
*
*/
- (void)calculateCacheSizeCompletionBlock:(SJCalculateSizeCompletionBlock _Nullable)completionBlock;
//================================= clear cache ==============================//
/**
* This method is used to clear all cache which is in the cache file
*
* @param completionBlock callback
*
*/
- (void)clearAllCacheCompletionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
/**
* This method is used to clear the cache which is related the specific url,
no matter what request method is or parameters are
*
* @param url the url of network request
* @param completionBlock callback
*
*/
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
/**
* This method is used to clear the cache which is related the specific url and method,
no matter what parameters are
*
* @param url the url of network request
* @param method request method
* @param completionBlock callback
*
*/
- (void)loadCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
completionBlock:(SJLoadCacheArrCompletionBlock _Nullable)completionBlock;
/**
* This method is used to clear cache which is related to a specific url,method and parameters
*
* @param url the url of the network request
* @param method the method of the network request
* @param parameters the parameters of the network request
* @param completionBlock callback
*
*/
- (void)clearCacheWithUrl:(NSString * _Nonnull)url
method:(NSString * _Nonnull)method
parameters:(id _Nonnull)parameters
completionBlock:(SJClearCacheCompletionBlock _Nullable)completionBlock;
#pragma mark- Request Info
/**
* This method is used to log all current requests' information
*/
- (void)logAllCurrentRequests;
/**
* This method is used to check if there is remaining curent request
*
* @return if there is remaining requests
*/
- (BOOL)remainingCurrentRequests;
/**
* This method is used to calculate the count of current requests
*
* @return the count of current requests
*/
- (NSInteger)currentRequestCount;
@end
================================================
FILE: SJNetwork/SJNetworkManager.m
================================================
//
// SJNetworkManager.m
// SJNetwork
//
// Created by Sun Shijie on 2017/8/16.
// Copyright © 2017年 Shijie. All rights reserved.
//
#import "SJNetworkManager.h"
#import "SJNetworkConfig.h"
#import "SJNetworkRequestPool.h"
#import "SJNetworkRequestEngine.h"
#import "SJNetworkUploadEngine.h"
#import "SJNetworkDownloadEngine.h"
@interface SJNetworkManager()
@property (nonatomic, strong) SJNetworkRequestEngine *requestEngine;
@property (nonatomic, strong) SJNetworkUploadEngine *uploadEngine;
@property (nonatomic, strong) SJNetworkDownloadEngine *downloadEngine;
@property (nonatomic, strong) SJNetworkRequestPool *requestPool;
@property (nonatomic, strong) SJNetworkCacheManager *cacheManager;
@end
@implementation SJNetworkManager
#pragma mark- ============== Life Cycle ===========
+ (SJNetworkManager *_Nullable)sharedManager {
static SJNetworkManager *sharedManager = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[SJNetworkManager alloc] init];
});
return sharedManager;
}
- (void)dealloc{
[self cancelAllCurrentRequests];
}
#pragma mark- ============== Public Methods ==============
- (void)addCustomHeader:(NSDictionary *_Nonnull)header{
[[SJNetworkConfig sharedConfig] addCustomHeader:header];
}
- (NSDictionary *_Nullable)customHeaders{
return [SJNetworkConfig sharedConfig].customHeaders;
}
#pragma mark- ============== Request API using GET method ==============
- (void)sendGetRequest:(NSString * _Nonnull)url
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:nil
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
- (void)sendGetRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
#pragma mark- ============== Request API using POST method ==============
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
- (void)sendPostRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
#pragma mark- ============== Request API using PUT method ==============
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPUT
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPUT
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPUT
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
- (void)sendPutRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodPUT
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
#pragma mark- ============== Request API using DELETE method ==============
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodDELETE
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodDELETE
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodDELETE
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
- (void)sendDeleteRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:SJRequestMethodDELETE
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
#pragma mark- ============== Request API using specific parameters ==============
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
if (parameters) {
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}else{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:nil
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
}
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
if (parameters) {
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}else{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:nil
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
}
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
if (parameters) {
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}else{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:nil
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
}
- (void)sendRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
if (parameters) {
[self.requestEngine sendRequest:url
method:SJRequestMethodPOST
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}else{
[self.requestEngine sendRequest:url
method:SJRequestMethodGET
parameters:nil
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
}
#pragma mark- ============== Request API using specific request method ==============
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:method
parameters:parameters
loadCache:NO
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:method
parameters:parameters
loadCache:loadCache
cacheDuration:0
success:successBlock
failure:failureBlock];
}
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:method
parameters:parameters
loadCache:NO
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
- (void)sendRequest:(NSString * _Nonnull)url
method:(SJRequestMethod)method
parameters:(id _Nullable)parameters
loadCache:(BOOL)loadCache
cacheDuration:(NSTimeInterval)cacheDuration
success:(SJSuccessBlock _Nullable)successBlock
failure:(SJFailureBlock _Nullable)failureBlock{
[self.requestEngine sendRequest:url
method:method
parameters:parameters
loadCache:loadCache
cacheDuration:cacheDuration
success:successBlock
failure:failureBlock];
}
#pragma mark- ============== Request API uploading ==============
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:NO
parameters:parameters
images:@[image]
compressRatio:1
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:ignoreBaseUrl
parameters:parameters
images:@[image]
compressRatio:1
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:NO
parameters:parameters
images:images
compressRatio:1
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:ignoreBaseUrl
parameters:parameters
images:images
compressRatio:1
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:NO
parameters:parameters
images:@[image]
compressRatio:compressRatio
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImageRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
image:(UIImage * _Nonnull)image
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:ignoreBaseUrl
parameters:parameters
images:@[image]
compressRatio:compressRatio
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:NO
parameters:parameters
images:images
compressRatio:compressRatio
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
- (void)sendUploadImagesRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
parameters:(id _Nullable)parameters
images:(NSArray<UIImage *> * _Nonnull)images
compressRatio:(float)compressRatio
name:(NSString * _Nonnull)name
mimeType:(NSString * _Nullable)mimeType
progress:(SJUploadProgressBlock _Nullable)uploadProgressBlock
success:(SJUploadSuccessBlock _Nullable)uploadSuccessBlock
failure:(SJUploadFailureBlock _Nullable)uploadFailureBlock{
[self.uploadEngine sendUploadImagesRequest:url
ignoreBaseUrl:ignoreBaseUrl
parameters:parameters
images:images
compressRatio:compressRatio
name:name
mimeType:mimeType
progress:uploadProgressBlock
success:uploadSuccessBlock
failure:uploadFailureBlock];
}
#pragma mark- ============== Request API downloading ==============
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:NO
downloadFilePath:downloadFilePath
resumable:YES
backgroundSupport:NO
progress:downloadProgressBlock
success:downloadSuccessBlock
failure:downloadFailureBlock];
}
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:ignoreBaseUrl
downloadFilePath:downloadFilePath
resumable:YES
backgroundSupport:NO
progress:downloadProgressBlock
success:downloadSuccessBlock
failure:downloadFailureBlock];
}
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:NO
downloadFilePath:downloadFilePath
resumable:resumable
backgroundSupport:NO
progress:downloadProgressBlock
success:downloadSuccessBlock
failure:downloadFailureBlock];
}
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
resumable:(BOOL)resumable
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:ignoreBaseUrl
downloadFilePath:downloadFilePath
resumable:resumable
backgroundSupport:NO
progress:downloadProgressBlock
success:downloadSuccessBlock
failure:downloadFailureBlock];
}
- (void)sendDownloadRequest:(NSString * _Nonnull)url
downloadFilePath:(NSString *_Nonnull)downloadFilePath
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:NO
downloadFilePath:downloadFilePath
resumable:YES
backgroundSupport:NO
progress:downloadProgressBlock
success:downloadSuccessBlock
failure:downloadFailureBlock];
}
- (void)sendDownloadRequest:(NSString * _Nonnull)url
ignoreBaseUrl:(BOOL)ignoreBaseUrl
downloadFilePath:(NSString *_Nonnull)downloadFilePath
backgroundSupport:(BOOL)backgroundSupport
progress:(SJDownloadProgressBlock _Nullable)downloadProgressBlock
success:(SJDownloadSuccessBlock _Nullable)downloadSuccessBlock
failure:(SJDownloadFailureBlock _Nullable)downloadFailureBlock{
[self.downloadEngine sendDownloadRequest:url
ignoreBaseUrl:ignoreBaseUrl
downloadFilePath:downloadFilePath
resumable:YES
backg
gitextract_p9vvfh07/
├── LICENSE
├── README.md
├── SJNetwork/
│ ├── SJNetwork.h
│ ├── SJNetworkBaseEngine.h
│ ├── SJNetworkBaseEngine.m
│ ├── SJNetworkCacheInfo.h
│ ├── SJNetworkCacheInfo.m
│ ├── SJNetworkCacheManager.h
│ ├── SJNetworkCacheManager.m
│ ├── SJNetworkConfig.h
│ ├── SJNetworkConfig.m
│ ├── SJNetworkDownloadEngine.h
│ ├── SJNetworkDownloadEngine.m
│ ├── SJNetworkDownloadResumeDataInfo.h
│ ├── SJNetworkDownloadResumeDataInfo.m
│ ├── SJNetworkHeader.h
│ ├── SJNetworkManager.h
│ ├── SJNetworkManager.m
│ ├── SJNetworkProtocol.h
│ ├── SJNetworkRequestEngine.h
│ ├── SJNetworkRequestEngine.m
│ ├── SJNetworkRequestModel.h
│ ├── SJNetworkRequestModel.m
│ ├── SJNetworkRequestPool.h
│ ├── SJNetworkRequestPool.m
│ ├── SJNetworkUploadEngine.h
│ ├── SJNetworkUploadEngine.m
│ ├── SJNetworkUtils.h
│ └── SJNetworkUtils.m
├── SJNetwork.podspec
└── SJNetworkDemo/
├── Podfile
├── Pods/
│ ├── AFNetworking/
│ │ ├── AFNetworking/
│ │ │ ├── AFHTTPSessionManager.h
│ │ │ ├── AFHTTPSessionManager.m
│ │ │ ├── AFNetworkReachabilityManager.h
│ │ │ ├── AFNetworkReachabilityManager.m
│ │ │ ├── AFNetworking.h
│ │ │ ├── AFSecurityPolicy.h
│ │ │ ├── AFSecurityPolicy.m
│ │ │ ├── AFURLRequestSerialization.h
│ │ │ ├── AFURLRequestSerialization.m
│ │ │ ├── AFURLResponseSerialization.h
│ │ │ ├── AFURLResponseSerialization.m
│ │ │ ├── AFURLSessionManager.h
│ │ │ └── AFURLSessionManager.m
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── UIKit+AFNetworking/
│ │ ├── AFAutoPurgingImageCache.h
│ │ ├── AFAutoPurgingImageCache.m
│ │ ├── AFImageDownloader.h
│ │ ├── AFImageDownloader.m
│ │ ├── AFNetworkActivityIndicatorManager.h
│ │ ├── AFNetworkActivityIndicatorManager.m
│ │ ├── UIActivityIndicatorView+AFNetworking.h
│ │ ├── UIActivityIndicatorView+AFNetworking.m
│ │ ├── UIButton+AFNetworking.h
│ │ ├── UIButton+AFNetworking.m
│ │ ├── UIImage+AFNetworking.h
│ │ ├── UIImageView+AFNetworking.h
│ │ ├── UIImageView+AFNetworking.m
│ │ ├── UIKit+AFNetworking.h
│ │ ├── UIProgressView+AFNetworking.h
│ │ ├── UIProgressView+AFNetworking.m
│ │ ├── UIRefreshControl+AFNetworking.h
│ │ ├── UIRefreshControl+AFNetworking.m
│ │ ├── UIWebView+AFNetworking.h
│ │ └── UIWebView+AFNetworking.m
│ ├── Pods.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── xcuserdata/
│ │ └── SunShijie.xcuserdatad/
│ │ └── xcschemes/
│ │ ├── AFNetworking.xcscheme
│ │ ├── Pods-SJNetworkingDemo.xcscheme
│ │ └── xcschememanagement.plist
│ └── Target Support Files/
│ ├── AFNetworking/
│ │ ├── AFNetworking-dummy.m
│ │ ├── AFNetworking-prefix.pch
│ │ └── AFNetworking.xcconfig
│ └── Pods-SJNetworkingDemo/
│ ├── Pods-SJNetworkingDemo-acknowledgements.markdown
│ ├── Pods-SJNetworkingDemo-acknowledgements.plist
│ ├── Pods-SJNetworkingDemo-dummy.m
│ ├── Pods-SJNetworkingDemo-frameworks.sh
│ ├── Pods-SJNetworkingDemo-resources.sh
│ ├── Pods-SJNetworkingDemo.debug.xcconfig
│ └── Pods-SJNetworkingDemo.release.xcconfig
├── SJNetworkingDemo/
│ ├── Other/
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
│ ├── SJNetwork/
│ │ ├── SJNetwork.h
│ │ ├── SJNetworkBaseEngine.h
│ │ ├── SJNetworkBaseEngine.m
│ │ ├── SJNetworkCacheInfo.h
│ │ ├── SJNetworkCacheInfo.m
│ │ ├── SJNetworkCacheManager.h
│ │ ├── SJNetworkCacheManager.m
│ │ ├── SJNetworkConfig.h
│ │ ├── SJNetworkConfig.m
│ │ ├── SJNetworkDownloadEngine.h
│ │ ├── SJNetworkDownloadEngine.m
│ │ ├── SJNetworkDownloadResumeDataInfo.h
│ │ ├── SJNetworkDownloadResumeDataInfo.m
│ │ ├── SJNetworkHeader.h
│ │ ├── SJNetworkManager.h
│ │ ├── SJNetworkManager.m
│ │ ├── SJNetworkProtocol.h
│ │ ├── SJNetworkRequestEngine.h
│ │ ├── SJNetworkRequestEngine.m
│ │ ├── SJNetworkRequestModel.h
│ │ ├── SJNetworkRequestModel.m
│ │ ├── SJNetworkRequestPool.h
│ │ ├── SJNetworkRequestPool.m
│ │ ├── SJNetworkUploadEngine.h
│ │ ├── SJNetworkUploadEngine.m
│ │ ├── SJNetworkUtils.h
│ │ └── SJNetworkUtils.m
│ └── ViewController/
│ ├── DownLoadViewController.h
│ ├── DownLoadViewController.m
│ ├── UploadViewController.h
│ ├── UploadViewController.m
│ ├── ViewController.h
│ └── ViewController.m
├── SJNetworkingDemo.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata/
│ │ └── SunShijie.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ └── SunShijie.xcuserdatad/
│ └── xcschemes/
│ ├── SJNetworkingDemo.xcscheme
│ └── xcschememanagement.plist
├── SJNetworkingDemo.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcuserdata/
│ └── SunShijie.xcuserdatad/
│ ├── UserInterfaceState (ruwang’s MacBook Air 的冲突副本 2017-11-24).xcuserstate
│ ├── UserInterfaceState (ruwang’s MacBook Air 的冲突副本 2017-11-28).xcuserstate
│ ├── UserInterfaceState.xcuserstate
│ └── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
├── SJNetworkingDemoTests/
│ ├── Info.plist
│ └── SJNetworkingDemoTests.m
└── SJNetworkingDemoUITests/
├── Info.plist
└── SJNetworkingDemoUITests.m
SYMBOL INDEX (3 symbols across 3 files)
FILE: SJNetwork/SJNetworkRequestPool.h
type NSMutableDictionary (line 29) | typedef NSMutableDictionary<NSString *, SJNetworkRequestModel *> SJCurre...
FILE: SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h
type AFSSLPinningModeNone (line 25) | typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
FILE: SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestPool.h
type NSMutableDictionary (line 29) | typedef NSMutableDictionary<NSString *, SJNetworkRequestModel *> SJCurre...
Condensed preview — 134 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,226K chars).
[
{
"path": "LICENSE",
"chars": 1066,
"preview": "MIT License\n\nCopyright (c) 2017 J_Knight_\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
},
{
"path": "README.md",
"chars": 18182,
"preview": "# SJNetwork\n\n\n 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permi"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m",
"chars": 15021,
"preview": "// AFHTTPSessionManager.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permi"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h",
"chars": 8066,
"preview": "// AFNetworkReachabilityManager.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m",
"chars": 9803,
"preview": "// AFNetworkReachabilityManager.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFNetworking.h",
"chars": 1599,
"preview": "// AFNetworking.h\n//\n// Copyright (c) 2013 AFNetworking (http://afnetworking.com/)\n// \n// Permission is hereby granted, "
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h",
"chars": 5898,
"preview": "// AFSecurityPolicy.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permissio"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m",
"chars": 12989,
"preview": "// AFSecurityPolicy.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permissio"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h",
"chars": 22819,
"preview": "// AFURLRequestSerialization.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// "
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m",
"chars": 51353,
"preview": "// AFURLRequestSerialization.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// "
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h",
"chars": 12236,
"preview": "// AFURLResponseSerialization.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n//"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m",
"chars": 27056,
"preview": "// AFURLResponseSerialization.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n//"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h",
"chars": 30163,
"preview": "// AFURLSessionManager.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permis"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m",
"chars": 55292,
"preview": "// AFURLSessionManager.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permis"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/LICENSE",
"chars": 1102,
"preview": "Copyright (c) 2011–2016 Alamofire Software Foundation (http://alamofire.org/)\n\nPermission is hereby granted, free of cha"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/README.md",
"chars": 14519,
"preview": "<p align=\"center\" >\n <img src=\"https://raw.github.com/AFNetworking/AFNetworking/assets/afnetworking-logo.png\" alt=\"AFNe"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFAutoPurgingImageCache.h",
"chars": 5847,
"preview": "// AFAutoPurgingImageCache.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Pe"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFAutoPurgingImageCache.m",
"chars": 7623,
"preview": "// AFAutoPurgingImageCache.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Pe"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.h",
"chars": 9076,
"preview": "// AFImageDownloader.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permissi"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m",
"chars": 17592,
"preview": "// AFImageDownloader.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Permissi"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h",
"chars": 5492,
"preview": "// AFNetworkActivityIndicatorManager.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ "
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m",
"chars": 9851,
"preview": "// AFNetworkActivityIndicatorManager.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ "
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h",
"chars": 2000,
"preview": "// UIActivityIndicatorView+AFNetworking.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.or"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m",
"chars": 5049,
"preview": "// UIActivityIndicatorView+AFNetworking.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.or"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h",
"chars": 10054,
"preview": "// UIButton+AFNetworking.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Perm"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m",
"chars": 12934,
"preview": "// UIButton+AFNetworking.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Perm"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIImage+AFNetworking.h",
"chars": 1312,
"preview": "//\n// UIImage+AFNetworking.h\n// \n//\n// Created by Paulo Ferreira on 08/07/15.\n//\n// Permission is hereby granted, fre"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h",
"chars": 5946,
"preview": "// UIImageView+AFNetworking.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// P"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m",
"chars": 6326,
"preview": "// UIImageView+AFNetworking.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// P"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h",
"chars": 1760,
"preview": "// UIKit+AFNetworking.h\n//\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Perm"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h",
"chars": 2468,
"preview": "// UIProgressView+AFNetworking.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n/"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m",
"chars": 5158,
"preview": "// UIProgressView+AFNetworking.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n/"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h",
"chars": 2011,
"preview": "// UIRefreshControl+AFNetworking.m\n//\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m",
"chars": 4800,
"preview": "// UIRefreshControl+AFNetworking.m\n//\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h",
"chars": 4529,
"preview": "// UIWebView+AFNetworking.h\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Per"
},
{
"path": "SJNetworkDemo/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m",
"chars": 6761,
"preview": "// UIWebView+AFNetworking.m\n// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )\n//\n// Per"
},
{
"path": "SJNetworkDemo/Pods/Pods.xcodeproj/project.pbxproj",
"chars": 44431,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "SJNetworkDemo/Pods/Pods.xcodeproj/xcuserdata/SunShijie.xcuserdatad/xcschemes/AFNetworking.xcscheme",
"chars": 2547,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "SJNetworkDemo/Pods/Pods.xcodeproj/xcuserdata/SunShijie.xcuserdatad/xcschemes/Pods-SJNetworkingDemo.xcscheme",
"chars": 2583,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "SJNetworkDemo/Pods/Pods.xcodeproj/xcuserdata/SunShijie.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 565,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m",
"chars": 128,
"preview": "#import <Foundation/Foundation.h>\n@interface PodsDummy_AFNetworking : NSObject\n@end\n@implementation PodsDummy_AFNetworki"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch",
"chars": 379,
"preview": "#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#else\n#ifndef FOUNDATION_EXPORT\n#if defined(__cplusplus)\n#define FOUNDATION_EXPO"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig",
"chars": 708,
"preview": "CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/AFNetworking\nGCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPO"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo-acknowledgements.markdown",
"chars": 1254,
"preview": "# Acknowledgements\nThis application makes use of the following third party libraries:\n\n## AFNetworking\n\nCopyright (c) 20"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo-acknowledgements.plist",
"chars": 2127,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo-dummy.m",
"chars": 146,
"preview": "#import <Foundation/Foundation.h>\n@interface PodsDummy_Pods_SJNetworkingDemo : NSObject\n@end\n@implementation PodsDummy_P"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo-frameworks.sh",
"chars": 4423,
"preview": "#!/bin/sh\nset -e\n\necho \"mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nmkdir -p \"${CONFIGURATION_BUILD_D"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo-resources.sh",
"chars": 5528,
"preview": "#!/bin/sh\nset -e\n\nmkdir -p \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\n\nRESOURCES_TO_COPY=${PODS_ROOT}/re"
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo.debug.xcconfig",
"chars": 712,
"preview": "GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1\nHEADER_SEARCH_PATHS = $(inherited) \"${PODS_ROOT}/Headers/Public\""
},
{
"path": "SJNetworkDemo/Pods/Target Support Files/Pods-SJNetworkingDemo/Pods-SJNetworkingDemo.release.xcconfig",
"chars": 712,
"preview": "GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1\nHEADER_SEARCH_PATHS = $(inherited) \"${PODS_ROOT}/Headers/Public\""
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/AppDelegate.h",
"chars": 284,
"preview": "//\n// AppDelegate.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/23.\n// Copyright © 2017年 Shijie. All "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/AppDelegate.m",
"chars": 2556,
"preview": "//\n// AppDelegate.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/23.\n// Copyright © 2017年 Shijie. All "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1495,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/Base.lproj/LaunchScreen.storyboard",
"chars": 1681,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/Base.lproj/Main.storyboard",
"chars": 56775,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/Info.plist",
"chars": 1561,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/Other/main.m",
"chars": 341,
"preview": "//\n// main.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/23.\n// Copyright © 2017年 Shijie. All rights "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetwork.h",
"chars": 263,
"preview": "//\n// SJNetwork.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/12/27.\n// Copyright © 2017年 Shijie. All ri"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkBaseEngine.h",
"chars": 906,
"preview": "//\n// SJNetworkBaseEngine.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/12/26.\n// Copyright © 2017年 Shij"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkBaseEngine.m",
"chars": 557,
"preview": "//\n// SJNetworkBaseEngine.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/12/26.\n// Copyright © 2017年 Shij"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkCacheInfo.h",
"chars": 940,
"preview": "//\n// SJNetworkCacheInfo.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年 Shiji"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkCacheInfo.m",
"chars": 1614,
"preview": "//\n// SJNetworkCacheInfo.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年 Shiji"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkCacheManager.h",
"chars": 6531,
"preview": "//\n// SJNetworkCache.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkCacheManager.m",
"chars": 23252,
"preview": "//\n// SJNetworkCache.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkConfig.h",
"chars": 1307,
"preview": "//\n// SJNetworkConfig.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All righ"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkConfig.m",
"chars": 1198,
"preview": "//\n// SJNetworkConfig.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All righ"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkDownloadEngine.h",
"chars": 6341,
"preview": "//\n// SJNetworkDownloadManager.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkDownloadEngine.m",
"chars": 53146,
"preview": "//\n// SJNetworkDownloadManager.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkDownloadResumeDataInfo.h",
"chars": 901,
"preview": "//\n// SJNetworkResumeDataInfo.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/28.\n// Copyright © 2017年 "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkDownloadResumeDataInfo.m",
"chars": 1598,
"preview": "//\n// SJNetworkResumeDataInfo.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/28.\n// Copyright © 2017年 "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkHeader.h",
"chars": 2019,
"preview": "//\n// SJNetworkHeader.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/12/26.\n// Copyright © 2017年 Shijie. "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkManager.h",
"chars": 43625,
"preview": "//\n// SJNetworkManager.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All rig"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkManager.m",
"chars": 43539,
"preview": "//\n// SJNetworkManager.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All rig"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkProtocol.h",
"chars": 515,
"preview": "//\n// SJNetworkProtocol.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/12/6.\n// Copyright © 2017年 Shijie."
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestEngine.h",
"chars": 2604,
"preview": "//\n// SJNetworkRequestManager.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/26.\n// Copyright © 2017年 "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestEngine.m",
"chars": 14135,
"preview": "//\n// SJNetworkRequestManager.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/26.\n// Copyright © 2017年 "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestModel.h",
"chars": 5345,
"preview": "//\n// SJNetworkRequestModel.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/17.\n// Copyright © 2017年 Shijie. Al"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestModel.m",
"chars": 5152,
"preview": "//\n// SJNetworkRequestModel.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/17.\n// Copyright © 2017年 Shijie. Al"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestPool.h",
"chars": 3417,
"preview": "//\n// SJNetworkRequestPool.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年 Shi"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkRequestPool.m",
"chars": 10403,
"preview": "//\n// SJNetworkRequestPool.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/25.\n// Copyright © 2017年 Shi"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkUploadEngine.h",
"chars": 2352,
"preview": "//\n// SJNetworkUploadManager.h\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/26.\n// Copyright © 2017年 S"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkUploadEngine.m",
"chars": 14825,
"preview": "//\n// SJNetworkUploadManager.m\n// SJNetworkingDemo\n//\n// Created by Sun Shijie on 2017/11/26.\n// Copyright © 2017年 S"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkUtils.h",
"chars": 5597,
"preview": "//\n// SJNetworkUtils.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/17.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/SJNetwork/SJNetworkUtils.m",
"chars": 10482,
"preview": "//\n// SJNetworkUtils.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/17.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/DownLoadViewController.h",
"chars": 227,
"preview": "//\n// DownLoadViewController.h\n// WWNetwork\n//\n// Created by Sun Shijie on 2017/9/9.\n// Copyright © 2017年 Shijie. Al"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/DownLoadViewController.m",
"chars": 8316,
"preview": "//\n// DownLoadViewController.m\n// WWNetwork\n//\n// Created by Sun Shijie on 2017/9/9.\n// Copyright © 2017年 Shijie. Al"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/UploadViewController.h",
"chars": 223,
"preview": "//\n// UploadViewController.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/9/9.\n// Copyright © 2017年 Shijie. All "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/UploadViewController.m",
"chars": 4199,
"preview": "//\n// UploadViewController.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/9/9.\n// Copyright © 2017年 Shijie. All "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/ViewController.h",
"chars": 214,
"preview": "//\n// ViewController.h\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo/ViewController/ViewController.m",
"chars": 10925,
"preview": "//\n// ViewController.m\n// SJNetwork\n//\n// Created by Sun Shijie on 2017/8/16.\n// Copyright © 2017年 Shijie. All right"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcodeproj/project.pbxproj",
"chars": 39955,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 161,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:SJNetworkingDem"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcodeproj/xcuserdata/SunShijie.xcuserdatad/xcschemes/SJNetworkingDemo.xcscheme",
"chars": 4369,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcodeproj/xcuserdata/SunShijie.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 668,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcworkspace/contents.xcworkspacedata",
"chars": 234,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:SJNetworkingDe"
},
{
"path": "SJNetworkDemo/SJNetworkingDemo.xcworkspace/xcuserdata/SunShijie.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
"chars": 7219,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n type = \"0\"\n version = \"2.0\">\n <Breakpoints>\n <BreakpointProxy"
},
{
"path": "SJNetworkDemo/SJNetworkingDemoTests/Info.plist",
"chars": 701,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/SJNetworkingDemoTests/SJNetworkingDemoTests.m",
"chars": 933,
"preview": "//\n// SJNetworkingDemoTests.m\n// SJNetworkingDemoTests\n//\n// Created by Sun Shijie on 2017/11/23.\n// Copyright © 201"
},
{
"path": "SJNetworkDemo/SJNetworkingDemoUITests/Info.plist",
"chars": 701,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "SJNetworkDemo/SJNetworkingDemoUITests/SJNetworkingDemoUITests.m",
"chars": 1240,
"preview": "//\n// SJNetworkingDemoUITests.m\n// SJNetworkingDemoUITests\n//\n// Created by Sun Shijie on 2017/11/23.\n// Copyright ©"
}
]
// ... and 4 more files (download for full content)
About this extraction
This page contains the full source code of the knightsj/SJNetwork GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 134 files (1.1 MB), approximately 255.5k tokens, and a symbol index with 3 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.