NoMoreNetworkService is designed to replace complex Network libraries with a philosophy of developing a simple and cohesive library that meets the data request, upload, and download needs of iOS applications.
Based entirely on URLSession and without defining new concepts, NoMoreNetworkService solely focuses on standardizing interface methods for consistent usage across data request, upload, and download tasks.
Furthermore, NoMoreNetworkService allows you to send data requests using a declarative syntax, enhancing the clarity and readability of your code.
- Simple and cohesive library: Emphasizes the library's straightforward design and consistency.
- Standardizing interface methods: Highlights the focus on creating a unified way to perform network operations.
- Declarative syntax: Explains that data requests can be expressed in a concise and readable manner.
- Clarity and transparency: Points out the improved readability and maintainability of the code.
- Xcode 15 +
- iOS 12 +
- Swift 5.9 +
NoMoreNetworkService is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'NoMoreNetworkService'
- Using
NetworkServiceBuilder
with custom configurations
NetworkServiceBuilder.default
.with(configuration: URLSessionConfiguration.ephemeral)
.with(options: NetworkServiceOptions(maxRetries: 3))
.build()
- Enable caching for the first load before fetching data from remote
NetworkServiceBuilder.default
.build()
.withDefaultCacheStorage()
- More advanced settings
NetworkServiceBuilder.default
.with(serverTrustConfiguration: ServerTrustConfiguration.default) // Enable SSL cert pinning
.appending(requestAdapter: AuthorizationRequestAdapter()) // Add request adapter interceptor
.appending(retrier: TokenRefreshRetrier()) // Add retrier interceptor
.build()
- Retrieves the contents of the specified URL
func fetchListOfEmployees() {
let url = URL(string: "https://your-domain.com/api/v1/employees")!
let urlRequest = URLRequest(url: url)
networkService.prepare(urlRequest: urlRequest)
.onProgress { percentage in
if percentage < 1 {
// Show loading view
} else {
// Hide loading view
}
}
.decodeResponse(to: Response<[Employee]>.self)
.onCompleted { result in
switch result.map({ $0.data }) {
case let .success(employees):
// Show list employees
print(">> Success: \(String(describing: employees))")
case let .failure(error):
// Show error
print(">> Failure: \(error)")
}
}
.send()
}
- Send request using NetworkRequestModel with JSON Encoding
The following is payload of body request to update employee information
{
"name": "Điện Biên Phủ",
"year_of_birth": 1954
}
Define request model with the properties corresponding to the fields in the payload
struct EmployeeUpdateRequest: EncodableNetworkRequestModel {
let name: String
let yearOfBirth: Int
/// These following conformation methods could be done by POP via protocol extensions
var host: String { "your-domain.com" }
var path: String { "/api/v1/employees" }
var method: String { "POST" }
}
Send request in global queue
let requestModel = EmployeeUpdateRequest(name: "Điện Biên Phủ", yearOfBirth: 1954)
service.prepare(requestWith: requestModel)
.weakTarget(self)
.onProgress { viewController, percent in
DispatchQueue.main.async { [weak viewController] in
if percent < 1 {
viewController?.activityIndicatorView.startAnimating()
viewController?.activityIndicatorView.isHidden = false
} else {
viewController?.activityIndicatorView.stopAnimating()
viewController?.activityIndicatorView.isHidden = true
}
}
}
.onCompleted { viewController, result in
DispatchQueue.main.async { [weak viewController] in
switch result {
case let .success:
viewController?.showSuccessMessage()
case let .failure(error):
viewController?.showError(message: error.localizedDescription)
}
}
}
.send(queue: .global())
func downloadFile() {
let url = URL(string: "https://file-examples.com/storage/file_example_PNG_3MB.png")!
let request = URLRequest(url: url)
networkService.prepare(urlRequest: request)
.forTask(.download(destinationURL: { suggestedFilename in
let fileManager = FileManager.default
let documentsDirectory = try! fileManager.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let url = documentsDirectory.appendingPathComponent(suggestedFilename ?? UUID().uuidString)
return url
}))
.weakTarget(self)
.onProgress(handler: { viewController, percent in
DispatchQueue.main.async { [weak viewController] in
if percent < 1 {
viewController?.progressView.isHidden = false
} else {
viewController?.progressView.isHidden = true
}
viewController?.progressView.progress = Float(percent)
}
})
.onCompleted(handler: { viewController, result in
DispatchQueue.main.async { [weak viewController] in
switch result {
case let .success(data):
viewController?.imageView.image = UIImage(data: data)
case let .failure(error):
let alert = UIAlertController(title: "Download failed", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel))
viewController?.present(alert, animated: true)
}
}
})
.send(queue: .global())
}
To run the example project, clone the repo, and run pod install
from the Example directory first.
congncif, congnc.if@gmail.com
NoMoreNetworkService is available under the MIT license. See the LICENSE file for more info.