Skip to content

Commit 478a8cb

Browse files
author
burak.uzunboy
committed
Initial commit
1 parent 7452930 commit 478a8cb

8 files changed

Lines changed: 737 additions & 5 deletions

File tree

Package.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import PackageDescription
55

66
let package = Package(
77
name: "iOSUsefulNetworkLayer",
8+
platforms: [.iOS(.v10)],
89
products: [
910
// Products define the executables and libraries produced by a package, and make them visible to other packages.
1011
.library(
@@ -13,16 +14,16 @@ let package = Package(
1314
],
1415
dependencies: [
1516
// Dependencies declare other packages that this package depends on.
16-
// .package(url: /* package url */, from: "1.0.0"),
17+
.package(url: "https://github.com/exozet/iOSCoreUsefulSDK", from: "1.0.0"),
1718
],
1819
targets: [
1920
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
2021
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
2122
.target(
2223
name: "iOSUsefulNetworkLayer",
23-
dependencies: []),
24+
dependencies: ["iOSCoreUsefulSDK"]),
2425
.testTarget(
2526
name: "iOSUsefulNetworkLayerTests",
26-
dependencies: ["iOSUsefulNetworkLayer"]),
27+
dependencies: ["iOSUsefulNetworkLayer", "iOSCoreUsefulSDK"]),
2728
]
2829
)

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
# iOSUsefulNetworkLayer
22

3-
A description of this package.
3+
### A most useful Network Layer written for iOS Projects.
4+
5+
## Installation
6+
7+
**iOSUsefulNetworkLayer** uses new Swift Package Manager which is easiest way introduced for iOS projects since from the beginning.
8+
9+
From Xcode simply select `File > Swift Packages > Add Package Dependency...` and paste `https://github.com/exozet/iOSUsefulNetworkLayer` to search field. You can specify rules according to your preferences and you are ready to use.
10+
11+
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
//
2+
// APIConfiguration.swift
3+
// DCA_iOS
4+
//
5+
// Created by Burak Uzunboy on 01.08.19.
6+
// Copyright © 2019 Exozet. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import iOSCoreUsefulSDK
11+
12+
/// Structure that keeps all information needed from Network Layer for operations.
13+
public struct APIConfiguration<T> where T: ResponseBodyParsable {
14+
/// Returns `URL` of the API request.
15+
var requestURL: URL
16+
17+
/// Type of the API request.
18+
var requestType: NetworkLayer.RequestType
19+
20+
/// Headers for the API request.
21+
var headers: [String:String]?
22+
23+
/// Request body for the API request.
24+
var body: [String:Any]?
25+
26+
/// The expected object type from the request.
27+
var responseBodyObject: T.Type
28+
29+
/// `NetworkLayer` priorities the API request by looking that parameter.
30+
var priority: Operation.QueuePriority
31+
32+
/// The desired expiration time for the API request.
33+
var cachingTime: NetworkLayer.CachingTime
34+
35+
/// `NetworkLayer` adds desired queue by looking that parameter.
36+
var isMainOperation: Bool
37+
38+
/// If `true`, the response will be cached by specified `cachingEndsAt` parameter of the response object.
39+
var autoCache: Bool
40+
41+
/// The timeout value for the request wait time.
42+
var timeOut: Int
43+
44+
/**
45+
Initializes Configuration with the host URL and endpoint separately.
46+
Returns nil if request URL cannot be created successfuly.
47+
- parameter isMainOperation: If `true`, operation will be performed in special queue and return to main queue.
48+
- parameter autoCache: To use that, override `cachingEndsAt:` method of Response Body Object.
49+
Then specified custom caching will be applied for that request.
50+
*/
51+
init?(hostURL: String, endPoint: String,
52+
requestType: NetworkLayer.RequestType = .get,
53+
headers: [String:String]? = nil,
54+
body: [String:Any]? = nil,
55+
responseBodyObject: T.Type,
56+
priority: Operation.QueuePriority = Operation.QueuePriority.normal,
57+
cachingTime: NetworkLayer.CachingTime = NetworkLayer.CachingTime(seconds: 60 * 60),
58+
isMainOperation: Bool = false,
59+
autoCache: Bool = false,
60+
timeOut: Int = 30) {
61+
62+
var url = URL(string: hostURL)
63+
url?.appendPathComponent(endPoint)
64+
guard let requestURL = url else { return nil }
65+
66+
self.requestURL = requestURL
67+
self.requestType = requestType
68+
self.headers = headers
69+
self.body = body
70+
self.responseBodyObject = responseBodyObject
71+
self.priority = priority
72+
self.cachingTime = cachingTime
73+
self.isMainOperation = isMainOperation
74+
self.autoCache = autoCache
75+
self.timeOut = timeOut
76+
}
77+
78+
/**
79+
Initializes Configuration with the URL
80+
- parameter isMainOperation: If `true`, operation will be performed in special queue and return to main queue.
81+
- parameter autoCache: To use that, override `cachingEndsAt:` method of Response Body Object.
82+
Then specified custom caching will be applied for that request.
83+
*/
84+
init(url: URL,
85+
requestType: NetworkLayer.RequestType = .get,
86+
headers: [String:String]? = nil,
87+
body: [String:Any]? = nil,
88+
responseBodyObject: T.Type,
89+
priority: Operation.QueuePriority = .normal,
90+
cachingTime: NetworkLayer.CachingTime = NetworkLayer.CachingTime(seconds: 60 * 60),
91+
isMainOperation: Bool = false,
92+
autoCache: Bool = false,
93+
timeOut: Int = 30) {
94+
95+
self.requestURL = url
96+
self.requestType = requestType
97+
self.headers = headers
98+
self.body = body
99+
self.responseBodyObject = responseBodyObject
100+
self.priority = priority
101+
self.cachingTime = cachingTime
102+
self.isMainOperation = isMainOperation
103+
self.autoCache = autoCache
104+
self.timeOut = timeOut
105+
}
106+
107+
/// Tries to create URL request by specified parameters.
108+
var request: URLRequest? {
109+
110+
// create url request with specified caching
111+
var request = URLRequest(url: self.requestURL,
112+
cachePolicy: .returnCacheDataElseLoad,
113+
timeoutInterval: TimeInterval(self.timeOut))
114+
115+
// set http method
116+
request.httpMethod = self.requestType.rawValue
117+
// set headers
118+
request.allHTTPHeaderFields = headers
119+
120+
// if request body is present, set json header and body together
121+
if let body = body {
122+
do {
123+
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
124+
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
125+
} catch {
126+
// error occurred
127+
return nil
128+
}
129+
}
130+
131+
return request
132+
}
133+
134+
/**
135+
Creates `APIOperation` for the specified task.
136+
- parameter task: The `URLSessionTask` created by the `NetworkLayer`
137+
- returns: `APIOperation` for the task and API configuration
138+
*/
139+
internal func operation(with task: URLSessionTask, id: Int) -> NetworkLayer.APIOperation {
140+
let operation = NetworkLayer.APIOperation(configuration: self, task: task, identifier: id)
141+
return operation
142+
}
143+
144+
}
145+
146+
/**
147+
The response objects should be inherited from the `ResponseBodyParsable` to operate by the `NetworkLayer`.
148+
*/
149+
open class ResponseBodyParsable: NSObject, NSDiscardableContent {
150+
151+
/// Returns creation date of the response by the `NetworkLayer`.
152+
public private(set) var creationDate: Date
153+
154+
/// Override this initializer to create responses from the `Data`.
155+
/// - parameter data: The response represented as `Data`
156+
required public init?(_ data: Data) {
157+
self.creationDate = Date()
158+
}
159+
160+
/// Override this initializer to create responses from the `JSON` object.
161+
/// - parameter response: The `JSON` object as `Any` type which could be casted to `Dictionary` or `Array`
162+
required public init?(_ response: Any?) {
163+
self.creationDate = Date()
164+
}
165+
166+
/// Returns `true` in default.
167+
public func beginContentAccess() -> Bool {
168+
print("\(self.typeName): Content access successful")
169+
return true
170+
}
171+
172+
/// Doesn't do anything in default.
173+
public func endContentAccess() {
174+
print("\(self.typeName): Content cannot be accessed anymore")
175+
}
176+
177+
/// Doesn't do anything in default.
178+
public func discardContentIfPossible() {
179+
print("\(self.typeName): Discard content called")
180+
}
181+
182+
/// Returns `false` in default.
183+
public func isContentDiscarded() -> Bool {
184+
return false
185+
}
186+
187+
/// Return specified parameter to work with `autoCache` API requests.
188+
public func cachingEndsAt() -> Date? {
189+
return nil
190+
}
191+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//
2+
// NetworkLayer+APIOperation.swift
3+
// DCA_iOS
4+
//
5+
// Created by Burak Uzunboy on 25.07.19.
6+
// Copyright © 2019 Exozet. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
extension NetworkLayer {
12+
13+
/// Wrapper class for NSOperation.
14+
class APIOperation: BlockOperation {
15+
/// `true`.
16+
override var isAsynchronous: Bool { return true }
17+
18+
/// returns internal property state.
19+
override var isFinished: Bool {
20+
get {
21+
return _isFinished
22+
}
23+
24+
set {
25+
willChangeValue(forKey: "isFinished")
26+
_isFinished = newValue
27+
didChangeValue(forKey: "isFinished")
28+
}
29+
}
30+
31+
/// internal property that holds the state.
32+
private var _isFinished: Bool = false
33+
34+
// MARK: Input properties
35+
36+
/// NetworkLayer instance to send messages.
37+
unowned var layerDelegate: NetworkLayer?
38+
39+
/// The task that will be operated by the `NetworkLayer`.
40+
var task: URLSessionTask
41+
42+
/// Unique identifier for the operation which created by the timestamp value.
43+
private(set) var identifier: Int
44+
45+
46+
/**
47+
Creates operation which includes URL task of the API.
48+
- parameter configuration: The API object which requests task.
49+
- parameter task: Task which will be operated for the API request.
50+
*/
51+
init<T>(configuration: APIConfiguration<T>, task: URLSessionTask, identifier: Int) where T: ResponseBodyParsable {
52+
self.task = task
53+
self.identifier = identifier
54+
super.init()
55+
self.name = String(task.taskIdentifier)
56+
}
57+
58+
/// Starts the URL task.
59+
override func start() {
60+
self.task.resume()
61+
self.layerDelegate?.sendLog(message: "Task with Operation ID: \(self.identifier) is started - URL: \(self.task.currentRequest?.url?.absoluteString ?? "nil")")
62+
}
63+
64+
/// Cancels the URL task.
65+
override func cancel() {
66+
self.task.cancel()
67+
self.layerDelegate?.sendLog(message: "Task with Operation ID: \(self.identifier) is canceled - URL: \(self.task.currentRequest?.url?.absoluteString ?? "nil")")
68+
}
69+
70+
/// Notifies `NetworkLayer` when deinitialization is completed.
71+
deinit {
72+
self.layerDelegate?.sendLog(message: "Operation with ID: \(self.identifier) is deinitializing")
73+
}
74+
75+
}
76+
77+
/// Defines available request types.
78+
enum RequestType: String {
79+
/// get type request
80+
case get = "GET"
81+
/// post type request
82+
case post = "POST"
83+
/// put type request
84+
case put = "PUT"
85+
/// delete type request
86+
case delete = "DELETE"
87+
}
88+
89+
}

0 commit comments

Comments
 (0)