Skip to content

Commit fd951e7

Browse files
author
burak.uzunboy
committed
Added class methods
1 parent ee8bafd commit fd951e7

5 files changed

Lines changed: 117 additions & 54 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/Packages
44
/*.xcodeproj
55
xcuserdata/
6+
/*.undocumented.json

Package.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ let package = Package(
2121
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
2222
.target(
2323
name: "iOSUsefulNetworkLayer",
24-
dependencies: ["iOSCoreUsefulSDK"])
24+
dependencies: ["iOSCoreUsefulSDK"]),
25+
// .testTarget(
26+
// name: "iOSUsefulNetworkLayerTests",
27+
// dependencies: ["iOSUsefulNetworkLayer", "iOSCoreUsefulSDK"]),
2528
]
2629
)

Sources/iOSUsefulNetworkLayer/NetworkLayer/NetworkLayer+Cache.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import UIKit
2828
extension NetworkLayer {
2929

3030
/// Custom Caching class.
31-
class Cache: URLCache {
31+
public class Cache: URLCache {
3232

3333
/// Default initializer.
3434
override init() {
@@ -111,7 +111,7 @@ extension NetworkLayer {
111111
}
112112

113113
/// Checks the response and acts accordingly.
114-
override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
114+
override public func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
115115
let cachedResponse = super.cachedResponse(for: request)
116116
let retVal = self.checkCachedResponse(cachedResponse)
117117
if retVal != nil {
@@ -127,12 +127,12 @@ extension NetworkLayer {
127127
}
128128

129129
/// Calls the super class.
130-
override func removeCachedResponses(since date: Date) {
130+
override public func removeCachedResponses(since date: Date) {
131131
super.removeCachedResponses(since: date)
132132
}
133133

134134
/// Checks the response and acts accordingly
135-
override func getCachedResponse(for dataTask: URLSessionDataTask, completionHandler: @escaping (CachedURLResponse?) -> Void) {
135+
override public func getCachedResponse(for dataTask: URLSessionDataTask, completionHandler: @escaping (CachedURLResponse?) -> Void) {
136136
super.getCachedResponse(for: dataTask) { (cachedResponse) in
137137
if let response = self.checkCachedResponse(cachedResponse) {
138138
completionHandler(response)
@@ -143,27 +143,27 @@ extension NetworkLayer {
143143
}
144144

145145
/// Calls the super class.
146-
override func removeCachedResponse(for request: URLRequest) {
146+
override public func removeCachedResponse(for request: URLRequest) {
147147
super.removeCachedResponse(for: request)
148148
}
149149

150150
/// Calls the super class.
151-
override func removeCachedResponse(for dataTask: URLSessionDataTask) {
151+
override public func removeCachedResponse(for dataTask: URLSessionDataTask) {
152152
super.removeCachedResponse(for: dataTask)
153153
}
154154

155155
/// Calls the super class.
156-
override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) {
156+
override public func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) {
157157
super.storeCachedResponse(cachedResponse, for: request)
158158
}
159159

160160
/// Calls the super class.
161-
override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for dataTask: URLSessionDataTask) {
161+
override public func storeCachedResponse(_ cachedResponse: CachedURLResponse, for dataTask: URLSessionDataTask) {
162162
super.storeCachedResponse(cachedResponse, for: dataTask)
163163
}
164164

165165
/// Calls the super class.
166-
override func removeAllCachedResponses() {
166+
override public func removeAllCachedResponses() {
167167
super.removeAllCachedResponses()
168168
}
169169

Sources/iOSUsefulNetworkLayer/NetworkLayer/NetworkLayer.swift

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
// THE SOFTWARE.
2222

2323
import Foundation
24+
import iOSCoreUsefulSDK
2425

2526
/**
2627
Base Network Layer that capable to cache and manage the operation queue.
@@ -41,8 +42,18 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
4142

4243
// MARK: - Properties
4344

45+
/// Holds cache of the `NetworkLayer`.
46+
public class var cache: Cache? {
47+
get { return NetworkLayer.shared._cache }
48+
}
49+
50+
public class var urlSession: URLSession {
51+
get { return NetworkLayer.shared._urlSession }
52+
set { NetworkLayer.shared._urlSession = newValue }
53+
}
54+
4455
/// Singleton instance for the `NetworkLayer`.
45-
public static let shared = NetworkLayer()
56+
private static let shared = NetworkLayer()
4657

4758
/// Operations marked as main are being handled by this queue.
4859
var mainQueue: OperationQueue {
@@ -59,14 +70,9 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
5970
self.backgroundQueue.qualityOfService = .default
6071
self.backgroundQueue.name = "\(Bundle.main.bundleIdentifier!).backgroundQueue"
6172
}}
62-
63-
/// Block that holds log message, level and caller function.
64-
public typealias LogListenerBlock = (_ message: String, _ func: String, _ level: LogType)->()
65-
/// Holds listener for the logs created by the `NetworkLayer`.
66-
private var logListener: LogListenerBlock?
67-
73+
6874
/// Holds cache of the `NetworkLayer`.
69-
var cache: Cache? {
75+
public var _cache: Cache? {
7076
get {
7177
return NetworkLayer.Cache(memoryCapacity: 0,
7278
diskCapacity: 150 * 1024 * 1024,
@@ -75,7 +81,7 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
7581
}
7682

7783
/// `URLSession` manager for the `NetworkLayer`.
78-
var urlSession: URLSession!
84+
public var _urlSession: URLSession!
7985

8086
/// Private initializer
8187
private override init() {
@@ -85,9 +91,9 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
8591

8692
let conf = URLSessionConfiguration.default
8793
conf.requestCachePolicy = .reloadIgnoringCacheData
88-
conf.urlCache = self.cache
94+
conf.urlCache = self._cache
8995

90-
self.urlSession = URLSession.init(configuration: conf,
96+
self._urlSession = URLSession.init(configuration: conf,
9197
delegate: self,
9298
delegateQueue: nil)
9399
}
@@ -106,11 +112,12 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
106112
- parameter error: Returns reason of the error if operation fails. `nil` otherwise
107113
- parameter response: Returns response with the specified type of response
108114
*/
109-
public func execute<T>(_ request: APIConfiguration<T>, completion: @escaping (Result<T>)->()) where T:ResponseBodyParsable {
110-
DispatchQueue.global().async { [unowned self] in
115+
public class func execute<T>(_ request: APIConfiguration<T>, completion: @escaping (Result<T>)->()) where T:ResponseBodyParsable {
116+
let instance = NetworkLayer.shared
117+
DispatchQueue.global().async {
111118
guard let urlRequest = request.request else {
112119
let err = NSError(domain: "", code: 500, description: "Cannot create URL Request with specified configurations")
113-
self.sendLog(message: err.localizedDescription, logType: .error(code: 900, name: err.localizedDescription))
120+
instance.sendLog(message: err.localizedDescription, logType: .error(code: 900, name: err.localizedDescription))
114121
DispatchQueue.main.async {
115122
completion(.error(err))
116123
}
@@ -122,28 +129,28 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
122129
var operation: APIOperation!
123130
var task: URLSessionDataTask!
124131

125-
task = self.urlSession.dataTask(with: urlRequest) { [unowned self](data, response, error) in
132+
task = instance._urlSession.dataTask(with: urlRequest) { (data, response, error) in
126133
guard operation != nil else { return }
127134

128-
self.sendLog(message: "Data Task for Operation ID: \(operation.identifier) is completed - URL: \(urlRequest.url?.absoluteString ?? "nil")")
135+
instance.sendLog(message: "Data Task for Operation ID: \(operation.identifier) is completed - URL: \(urlRequest.url?.absoluteString ?? "nil")")
129136
operation.isFinished = true
130137
var dataResult = data
131138
var loadedResponse = response
132139

133140
if let error = error {
134-
if let oldCacheObject = self.cache?.cachedResponseWithForce(for: urlRequest) {
141+
if let oldCacheObject = instance._cache?.cachedResponseWithForce(for: urlRequest) {
135142
dataResult = oldCacheObject.data
136143
loadedResponse = oldCacheObject.response
137144
} else {
138-
self.sendLog(message: "Operation:\(operation.identifier) failed with error: \(error.localizedDescription)", logType: .error(code: (error as NSError).code, name: error.localizedDescription))
145+
instance.sendLog(message: "Operation:\(operation.identifier) failed with error: \(error.localizedDescription)", logType: .error(code: (error as NSError).code, name: error.localizedDescription))
139146
DispatchQueue.main.async {
140147
completion(.error(error as NSError))
141148
}
142149
return
143150
}
144151
}
145152

146-
self.cache?.changeCacheExpiry(for: task, to: request.cachingTime.expirationDate ?? Date())
153+
instance._cache?.changeCacheExpiry(for: task, to: request.cachingTime.expirationDate ?? Date())
147154

148155
guard let data = dataResult, let loadResponse = loadedResponse else {
149156
let err = NSError(domain: "", code: 500, description: "Data is empty - Operation: \(operation.identifier)")
@@ -153,30 +160,30 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
153160
return
154161
}
155162

156-
self.proceedResponse(response: loadResponse, data: data, operationId: operation.identifier, request: request, completion: completion)
163+
instance.proceedResponse(response: loadResponse, data: data, operationId: operation.identifier, request: request, completion: completion)
157164
}
158165

159-
self.cache?.getCachedResponse(for: task, completionHandler: { (response) in
166+
instance._cache?.getCachedResponse(for: task, completionHandler: { (response) in
160167
if let response = response {
161168
// found in the cache, proceed
162-
self.sendLog(message: "Operation with ID: \(id) is gathered from the cache - Caching ends: \(response.userInfo?["cachingEndsAt"] ?? "Nil")")
163-
self.proceedResponse(response: response.response,
169+
instance.sendLog(message: "Operation with ID: \(id) is gathered from the cache - Caching ends: \(response.userInfo?["cachingEndsAt"] ?? "Nil")")
170+
instance.proceedResponse(response: response.response,
164171
data: response.data,
165172
operationId: id,
166173
request: request,
167174
completion: completion)
168175
task.cancel()
169176
} else {
170177
operation = request.operation(with: task, id: id)
171-
self.sendLog(message: "Operation with ID: \(operation.identifier) is created - URL: \(request.requestURL)")
172-
operation.layerDelegate = self
173-
request.isMainOperation ? self.mainQueue.addOperation(operation) : self.backgroundQueue.addOperation(operation)
178+
instance.sendLog(message: "Operation with ID: \(operation.identifier) is created - URL: \(request.requestURL)")
179+
operation.layerDelegate = instance
180+
request.isMainOperation ? instance.mainQueue.addOperation(operation) : instance.backgroundQueue.addOperation(operation)
174181

175-
operation.completionBlock = { [unowned self] in
176-
self.sendLog(message: "Operation with ID: \(operation.identifier) is completed")
182+
operation.completionBlock = {
183+
instance.sendLog(message: "Operation with ID: \(operation.identifier) is completed")
177184
}
178185

179-
self.sendLog(message: "Operation with ID: \(operation.identifier) is added to queue - isMainQueue: \(request.isMainOperation)")
186+
instance.sendLog(message: "Operation with ID: \(operation.identifier) is added to queue - isMainQueue: \(request.isMainOperation)")
180187
}
181188
})
182189
}
@@ -191,7 +198,7 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
191198
if let dataObject = request.responseBodyObject.init(data) {
192199
self.sendLog(message: "Data Object created from Operation: \(operationId) - Object: \(dataObject.typeName)")
193200
if request.autoCache, let cacheTiming = dataObject.cachingEndsAt() {
194-
self.cache?.changeCacheExpiry(for: request.request!, to: cacheTiming)
201+
self._cache?.changeCacheExpiry(for: request.request!, to: cacheTiming)
195202
}
196203
DispatchQueue.main.async {
197204
completion(.success(dataObject))
@@ -204,7 +211,7 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
204211
if let responseObject = request.responseBodyObject.init(json) {
205212
self.sendLog(message: "Response Object Created from JSON Data with Operation: \(operationId) - Object: \(responseObject.typeName)")
206213
if request.autoCache, let cacheTiming = responseObject.cachingEndsAt() {
207-
self.cache?.changeCacheExpiry(for: request.request!, to: cacheTiming)
214+
self._cache?.changeCacheExpiry(for: request.request!, to: cacheTiming)
208215
}
209216
DispatchQueue.main.async {
210217
completion(.success(responseObject))
@@ -225,16 +232,6 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
225232
}
226233
}
227234

228-
/**
229-
Sets listener for the log messages coming from the `NetworkLayer`.
230-
- parameter listener: Listener Block
231-
- parameter message: Message of the log
232-
- parameter func: Function who creates the log
233-
*/
234-
public func setLogListener(_ listener: @escaping LogListenerBlock) {
235-
self.logListener = listener
236-
}
237-
238235
// MARK: Private Methods
239236

240237
/**
@@ -243,11 +240,16 @@ public class NetworkLayer: NSObject, URLSessionDataDelegate {
243240
- parameter function: Caller of the log
244241
*/
245242
internal func sendLog(message: String, function: String = #function, logType: LogType = .info) {
246-
self.logListener?(message, function, logType)
243+
switch logType {
244+
case .info:
245+
LoggingManager.info(message: message, domain: .service, function: function)
246+
case .error(code: let code, name: let name):
247+
LoggingManager.error(message: message, domain: .service, function: function, tracking: (code, name))
248+
}
247249
}
248250

249251
/// Two log type is currently possible. Info or error with the code and name.
250-
public enum LogType {
252+
internal enum LogType {
251253
/// Default log type for the network layer
252254
case info
253255
/// Logs with the code and name of the error

Tests/iOSUsefulNetworkLayerTests/iOSUsefulNetworkLayerTests.swift

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,67 @@ final class iOSUsefulNetworkLayerTests: XCTestCase {
66
// This is an example of a functional test case.
77
// Use XCTAssert and related functions to verify your tests produce the correct
88
// results.
9-
XCTAssertEqual(iOSUsefulNetworkLayer().text, "Hello, World!")
9+
XCTAssertEqual(iOSUsefulNetworkLayer().text, "Hello, iOSUsefulNetworkLayer!")
10+
}
11+
12+
func testNetworkLayer() {
13+
let exp = XCTestExpectation(description: "Network layer should response success")
14+
15+
let api = APIConfiguration(hostURL: "https://jsonplaceholder.typicode.com",
16+
endPoint: "todos/1",
17+
requestType: .get,
18+
headers: nil, body: nil,
19+
responseBodyObject: ExampleResponseObject.self,
20+
priority: .low,
21+
cachingTime: .init(seconds: 60),
22+
isMainOperation: false, autoCache: true)
23+
24+
guard let apiReq = api else {
25+
XCTFail()
26+
return
27+
}
28+
29+
NetworkLayer.execute(apiReq) { (result) in
30+
switch result {
31+
case .error(let err):
32+
XCTFail("Error: \(err.localizedDescription)")
33+
break
34+
case .success(_):
35+
exp.fulfill()
36+
}
37+
}
38+
39+
wait(for: [exp], timeout: 5)
1040
}
1141

1242
static var allTests = [
1343
("testExample", testExample),
44+
("testNetworkLayer", testNetworkLayer)
1445
]
1546
}
47+
48+
class ExampleResponseObject: ResponseBodyParsable {
49+
50+
var userId: Int
51+
var id: Int
52+
var title: String
53+
var completed: Bool
54+
55+
required init?(_ data: Data) {
56+
return nil
57+
}
58+
59+
required init?(_ response: Any?) {
60+
guard let dict = response as? [String:Any] else { return nil }
61+
guard let userId = dict["userId"] as? Int,
62+
let id = dict["id"] as? Int,
63+
let title = dict["title"] as? String,
64+
let completed = dict["completed"] as? Bool else { return nil }
65+
66+
self.userId = userId
67+
self.id = id
68+
self.title = title
69+
self.completed = completed
70+
super.init(response)
71+
}
72+
}

0 commit comments

Comments
 (0)