How to show and hide loader on Network layer in swiftUI? - ios

I have a Global Singleton network class which handles the response of the API. I want to handle the loader from this class I don't want to manage from each ViewModel individually. I just want to toggle variabe "isLoading" in the ContentView from my global Network class "APIService" But no idea how would I do that?
class APIService {
static let shared = APIService()
private let timeInterval = 60
func makeApiTypeRequest<T: Codable>(
url: String,
param: [String: Any]? = nil,
methodType: HttpMethodType,
expecting: T.Type,
passToken: Bool = true,
completion: #escaping (Result<T, Error>)->Void) {
guard let url = URL(string: url) else {
return
}
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: TimeInterval(timeInterval))
if let param = param {
let finalData = try? JSONSerialization.data(withJSONObject: param)
request.httpBody = finalData
}
request.httpMethod = methodType.rawValue //"post"
request.addValue("application/json", forHTTPHeaderField: "content-type")
if passToken {
let data = KeychainHelper.standard.read(service: Constant.tokenKey)
if let data = data {
let accessToken = String(data: data, encoding: .utf8)
if let accessToken, accessToken != "" {
let headers = ["Content-Type": "application/json", "Authorization": "Bearer " + accessToken]
request.allHTTPHeaderFields = headers
}
}
}
URLSession.shared.dataTask(with: request) { (data,response,error) in
do {
if let error = error {
completion(.failure(error))
return
}
if let data = data {
if let httpStatus = response as? HTTPURLResponse {
switch httpStatus.statusCode {
case 400:
completion(.failure(CustomError.forbidden))
case 200:
let respObj = try JSONDecoder().decode(T.self, from: data)
completion(.success(respObj))
case 500:
// token expired
DispatchQueue.main.async {
NotificationCenter.default.post(name: Notification.Name("test.token.expired"), object: nil)
}
completion(.failure(CustomError.tokenExpired))
default:
completion(.failure(CustomError.unknown))
}
}
} else {
completion(.failure(CustomError.unknown))
print("no data found")
}
} catch(let error) {
completion(.failure(CustomError.unknown))
print("Error A123 \(error.localizedDescription)")
}
}.resume()
}
}
ContenView
struct ContentView: View {
#EnvironmentObject var session: SessionManager
#State var showMenu: Bool = false
#State var isLoading: Bool = false
#State var isAppInstalled: Bool = false
let pub = NotificationCenter.default
.publisher(for: NSNotification.Name("test.token.expired"))
var body: some View {
return NavigationView {
ZStack {
if isAppInstalled {
if session.currentUserState == .loggedIn {
GeometryReader { geometry in
TabContainer(showMenu: $showMenu)
.frame(width: geometry.size.width, height: geometry.size.height)
if self.showMenu {
MenuView()
.frame(width: geometry.size.width/2)
}
}
} else {
LoginView(showMenu: $showMenu)
}
if isLoading {
Loading()
.ignoresSafeArea()
}
} else {
GettingStartedView(isInstalled: $isAppInstalled)
}
}
.onAppear {
if GettingStartedPersistance.shared.isAppAlreadyInstalled() {
isAppInstalled = true
}
}
.onReceive(pub) { (output) in
self.session.signout()
}
}//.allowsHitTesting(!self.isLoading)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sample ViewModel
class LoginViewModel: ObservableObject {
#Published var loginResponse:LoginResponseModel?
#Published var isNavigatedToDashBaord = false
#Published var errorMessage = ""
#Published var isErrorPresented = false
private func validateInputFields(email: String, password: String)->Bool {
if email.isEmpty {
errorOccured(err: "Please enter email")
return false
}
if password.isEmpty {
errorOccured(err: "Please enter password")
return false
}
if !Utils.shared.isValidEmail(strToValidate: email) {
errorOccured(err: "Please enter a valid email")
return false
}
if password.count < 5 {
errorOccured(err: "Password must be atleast 5 characters long")
return false
}
return true
}
func login(email: String, password: String, completion: #escaping (()->())) {
if !validateInputFields(email: email, password: password) {
completion()
return
}
var param = [String: Any]()
param["username"] = email
param["password"] = password
APIService.shared.makeApiTypeRequest(url: APIURLConstant.loginUrl, param: param, methodType: .post, expecting: LoginResponseModel.self, passToken: false) { result in
switch result {
case .success(let loginData):
if loginData.authToken != "" && loginData.authToken != nil {
DispatchQueue.main.async {
self.saveUserToken(token: loginData.authToken ?? "")
self.loginResponse = loginData
self.successlogIn()
completion()
}
} else {
self.errorOccured(err: "Login failled")
completion()
}
case .failure( _):
self.errorOccured(err: "Login failled")
completion()
}
}
}
private func errorOccured(err: String) {
DispatchQueue.main.async {
self.errorMessage = err
self.isErrorPresented = true
}
}
private func successlogIn() {
DispatchQueue.main.async {
self.errorMessage = ""
self.isErrorPresented = false
self.isNavigatedToDashBaord = true
}
}
private func saveUserToken(token: String) {
let accessToken = Data(token.utf8)
KeychainHelper.standard.save(accessToken, service: Constant.tokenKey)
}
}

Related

I can't display String from API to View

I tried to store the text in a variable of API
in the class
I do not want to transfer the entire model, I want to transfer the text as it is here
class Api : ObservableObject{
#Published var title : String = ""
#Published var details : String = ""
func getDataModelApi () {
guard let url = URL(string: APIgetURL.demo) else { return }
var request = URLRequest(url: url)
let token = "38|xxxxx"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, responce, err in
guard let data = data else { return }
do {
let dataModel = try JSONDecoder().decode([model].self, from: data)
for i in dataModel {
DispatchQueue.main.async {
self.title = i.title
self.details = i.details
}
}
} catch {
print("error: ", error)
}
}
.resume()
}
}
In the title variable, the value was stored successfully, but the display in the view does not get anything
struct ContentView: View {
#StateObject var model3 = Api()
var body: some View {
VStack {
Text(model3.title)
}
.onAppear() {
Api().getDataModelApi()
}
}
}
Here in getData, it shows the complete model and needs a link, which I want to access from getDataModelApi
#Published var models : [model] = []
func getData (url : String) {
guard let url = URL(string: url) else { return }
var request = URLRequest(url: url)
let token = "38|xxx"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, responce, err in
guard let data = data else { return }
do {
let dataModel = try JSONDecoder().decode([model].self, from: data)
DispatchQueue.main.async {
self.models = dataModel
}
} catch {
print("error: ", error)
}
}
.resume()
}
You are using two different instances of Api and you throw away the second one in onAppear.
Replace
.onAppear() {
Api().getDataModelApi()
}
With
.onAppear() {
model3.getDataModelApi()
}

Receipt of notification of the arrival of new data from API

I have data on from the api on my app
I am sending the new data from my site
I want to put a message or notification on the application about the arrival of new data for this API
What is the best way to do this task?
This is the data I got
struct VideoView_Msrhiat: View {
#StateObject var model = Api()
var body: some View {
VStack {
ScrollView(.vertical, showsIndicators: false) {
ForEach(model.models) { item in
VStack {
Text(item.title)
}
}
}
.onAppear() {
model.getData(url: APIgetURL.Tap1)
}
}
}
Also
struct model : Identifiable, Codable {
let id = UUID()
var color : String?
var details : String
}
class Api : ObservableObject{
#Published var models : [model] = []
func getData (url : String) {
guard let url = URL(string: url) else { return }
var request = URLRequest(url: url)
let token = "38|Xxxx"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, responce, err in
guard let data = data else { return }
do {
let dataModel = try JSONDecoder().decode([model].self, from: data)
DispatchQueue.main.async {
self.models = dataModel
} catch {
print("error: ", error)
}
}
resume()
}
}

Updating List from JSON data SwiftUI

I'm having a hard time understanding how JSON data is supposed to be updated in a List in SwiftUI. I'm fetching data from NewsAPI.org, my list and detail views work just fine. I'm trying to figure out how to keep the list up-to-date when my json data changes, but the data remains outdated. I'm still a beginner to swift so if I made a mistake any help would be greatly appreciated.
UPDATED
Attempted to use combine with the same results, outdated data
New data class
class NewsData: ObservableObject {
var objectWillChange = PassthroughSubject<NewsData, Never>()
#Published var articles = [Article]() {
willSet {
objectWillChange.send(self)
}
}
init() {
guard let url = URL(string: "http://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY") else { return }
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode(News.self, from: data) {
DispatchQueue.main.async() {
self.articles = response.articles
}
}
}
}
.resume()
}
/*
init() {
URLSession.shared
.dataTaskPublisher(for: URLRequest(url: URL(string: "http://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY")!))
.map(\.data)
.decode(type: News.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
print(error.localizedDescription)
}
}, receiveValue: { data in
self.articles = data.articles
})
.store(in: &self.cancellables)
}
*/
/*
init() {
load()
}
func load() {
guard let url = URL(string: "http://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY") else { return }
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode(News.self, from: data) {
DispatchQueue.main.async() {
self.articles = response.articles
}
}
}
}
.resume()
}
*/
}
My data old class
struct News : Codable {
var articles : [Article]
}
struct Article : Codable {
let description : String?
let title : String?
let author: String?
let source: Source
let content: String?
let publishedAt: String?
}
struct Source: Codable {
let name: String?
}
class NewsData: ObservableObject {
#Published var news: News = News(articles: [])
init() {
load()
}
func load() {
guard let url = URL(string: "http://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY_HERE") else { return }
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode(News.self, from: data) {
DispatchQueue.main.async() {
self.news = response
}
}
}
}
.resume()
}
}
My ContentView
func relativeDate(date: String) -> String {
let formatter = RelativeDateTimeFormatter()
let dateFormatter = ISO8601DateFormatter()
return formatter.localizedString(for: dateFormatter.date(from: date) ?? Date(), relativeTo: Date())
}
struct ContentView: View {
#ObservedObject var news: NewsData
var body: some View {
NavigationView {
List(news.news.articles , id: \.title) { article in
VStack (alignment: .leading, spacing: 5){
Text(article.title ?? "")
.fontWeight(.bold)
.font(.subheadline)
.lineLimit(1)
Text(article.description ?? "")
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(1)
Text(relativeDate(date: article.publishedAt ?? ""))
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.navigationTitle("News")
}
}
}

Swift map Algolia hit to Model

I need to map the JSON object from Algolia to a Model.
Here's my ViewModel:
import Foundation
import AlgoliaSearchClient
class AlgoliaViewModel: ObservableObject {
#Published var idList: [MySearchModel] = []
func search(text: String, index: String) {
let client = SearchClient(appID: "XXX", apiKey: "XXX")
let index = client.index(withName: IndexName(rawValue: index))
let query = Query(text)
index.search(query: query) { result in
if case .success(let response) = result {
print("Response: \(response)")
do {
let hits: Array = response.hits
DispatchQueue.main.async {
self.idList = hits.map({
MySearchModel(searchValue: $0.objectID.rawValue)
})
print(self.idList)
}
}
catch {
print("JSONSerialization error:", error)
}
}
}
}
}
For the moment, I just have a Model with the objectID as searchValue.
How can I access to all other attributes of my Object and map them to a Model?
import Foundation
import AlgoliaSearchClient
class AlgoliaViewModel: ObservableObject {
#Published var list: [MySearchModel] = []
func search(text: String, index: String) {
let client = SearchClient(appID: "XXX", apiKey: "XXX")
let index = client.index(withName: IndexName(rawValue: index))
let query = Query(text)
index.search(query: query) { result in
if case .success(let response) = result {
print("Response: \(response)")
do {
let hits: Array = response.hits
DispatchQueue.main.async {
self.list = hits.map({MySearchModel.init})
print(self.list)
}
}
catch {
print("JSONSerialization error:", error)
}
}
}
}
}

How to call REST full API by providing headers in Swift

I am quite new to Swift,
we have a API server where we need to pass HEADERS like this:
Content-Type:application/json
Session:fb4e7f9b-0f31-4709-
I was looking in Google, the most basic example uses HTTP url call (i.e GET,POST)
Do I need to use some third-party product to call REST API by providing headers?
I would appreciate if you provide some guideline and possibly some example articles where it's showing how do to REST API call by providing different type HEADERs.
By using Alamofire it's pretty simple.
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"Session": "fb4e7f9b-0f31-4709-"
]
Alamofire.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
//Parse or print your response.
}
By using urlRequest
let header: HTTPHeaders = [
"Content-Type": "application/json",
"Session": "fb4e7f9b-0f31-4709-"
]
var urlRequest = URLRequest(url: URL(string: "your request url goes here."), cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10)
urlRequest.allHTTPHeaderFields = header
urlRequest.httpMethod = //.get, .post, .put
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let error = error {
print(error)
} else if let data = data ,let responseCode = response as? HTTPURLResponse {
do {
// Parse your response here.
}
}
catch let parseJSONError {
print("error on parsing request to JSON : \(parseJSONError)")
}
}
}.resume()
import Foundation
let url = URL(string: "")!
var request = URLRequest(url: url)
request.allHTTPHeaderFields = [
"Content-Type": "application/json",
"Session": "fb4e7f9b-0f31-4709-"
]
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else { return }
guard let data = data, let response = response else { return }
// handle data
}.resume()
The URLRequest type documentation outlines all of the different properties you can set. You need to create a URLRequest instance and then use URLSession to perform the request.
with header fields
static func getFeed(Completion:#escaping(FeedElement)->Void)
{
let urlString = NSString(format: "https://api-nhdev.india.com/api/v1/feeds/1/10/Kondapur") as String
guard let url = URL(string:urlString)
else {
return
}
let header: HTTPHeaders = [
"Authorization": YOUR_AUTH_ID
]
let request = NSMutableURLRequest(url: url as URL)
request.allHTTPHeaderFields = header
request.httpMethod = "GET"
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do{
//here dataResponse received from a network request
let decoder = JSONDecoder()
let codabledata = try decoder.decode(FeedElement.self, from: dataResponse)
print(codabledata)
//Response result
Completion(codabledata)
} catch let parsingError {
print("Error", parsingError)
}
}
mData.resume()
}
}
extension URL
{
init(baseUrl: String, path: String, method: RequestMethod, params: [String:Any])
{
var components = URLComponents(string: baseUrl)!
components.path += path
switch method {
case .get,.delete:
var queryItems = components.queryItems ?? []
queryItems.append(contentsOf: params.map {
URLQueryItem(name: $0.key, value: String(describing: $0.value))
})
//print(queryItems)
components.queryItems = queryItems
default:
break
}
//print(components.url!)
self = components.url!
}
}
extension URLRequest
{
init(baseUrl: String, path: String, method: RequestMethod, params: [String:Any]) {
let url = URL(baseUrl: baseUrl, path: path, method: method, params: params)
//////////////My Code For Remove Percentages In URL//////////////////////////
let urlWithPath = url.absoluteString.removingPercentEncoding
let absoluteUrl = URL(string: urlWithPath!)!
self.init(url: absoluteUrl)
//self.init(url: url)
let util = AuthToken.shared()
httpMethod = method.rawValue
setValue("application/json", forHTTPHeaderField: "Content-Type")
if util.getToken() != "" {
setValue(util.getToken(), forHTTPHeaderField: "Token")
}
switch method {
case .post, .put:
httpBody = try! JSONSerialization.data(withJSONObject: params, options: [])
default:
break
}
}
}
struct NetworkManager {
static let environment : NetworkEnvironment = .qa
private init(){}
static let shared = NetworkManager();
private var baseURL = APIEndPoint.baseURL
func load(path:String, method:RequestMethod, params:[String:Any], completion:#escaping(_ responseObject:Data?, _ error:Error?, _ isSuccess: Bool?) -> Void) -> Void{
let reachability = Reachability()
if(reachability?.connection == .wifi || reachability?.connection == .cellular)
{
// Creating the URLRequest object
let request = URLRequest(baseUrl: baseURL, path: path, method: method, params: params)
let task = URLSession.shared.dataTask(with: request) {
(data, response, error) in
if error != nil
{
completion(nil, nil, false)
}
else
{
completion(data, nil, true)
}
}
task.resume()
}
else
{
completion(nil, nil, false)
}
}
}
// MARK: - get user list
func getUserList(param : [String:Any]) {
NetworkManager.shared.load(path: APIEndPoint.homeURL, method: .get, params: param) { (data, error, response) in
if response!
{
guard let responseData = data else {
return
}
do {
print(responseData)
let jsonData = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers)
print(jsonData)
let apiResponse = try JSONDecoder().decode(User.self, from: responseData)
self.userList = apiResponse
self.delegate?.getUserListCompleted()
}catch {
print(error)
}
}
}
}
// MARK : Declare base URL
enum NetworkEnvironment {
case qa
case production
}
class APIEndPoint {
// MARK : Returning base URL
static var environmentBaseURL : String {
switch NetworkManager.environment {
case .production: return ""
case .qa: return "https://www.jsonkeeper.com/"
}
}
// MARK : Finally seted base URL for the end point
static var baseURL: String {
return environmentBaseURL
}
// MARK : List of sub URLs
static let homeURL = "b/12D8"
}
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
case UnableToGetInitialFlags
}
#available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
public extension Notification.Name {
static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
#available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
#available(*, deprecated, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
#available(*, deprecated, renamed: "connection.description")
public var currentReachabilityString: String {
return "\(connection)"
}
#available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
if flags == nil {
try? setReachabilityFlags()
}
switch flags?.connection {
case .none?, nil: return .none
case .cellular?: return allowsCellularConnection ? .cellular : .none
case .wifi?: return .wifi
}
}
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue: DispatchQueue
fileprivate(set) var flags: SCNetworkReachabilityFlags? {
didSet {
guard flags != oldValue else { return }
reachabilityChanged()
}
}
required public init(reachabilityRef: SCNetworkReachability, queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) {
self.allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability", qos: queueQoS, target: targetQueue)
}
public convenience init?(hostname: String, queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue)
}
public convenience init?(queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.flags = flags
}
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
try setReachabilityFlags()
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
#available(*, deprecated, message: "Please use `connection != .none`")
var isReachable: Bool {
return connection != .none
}
#available(*, deprecated, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return connection == .cellular
}
#available(*, deprecated, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
return connection == .wifi
}
var description: String {
guard let flags = flags else { return "unavailable flags" }
let W = isRunningOnDevice ? (flags.isOnWWANFlagSet ? "W" : "-") : "X"
let R = flags.isReachableFlagSet ? "R" : "-"
let c = flags.isConnectionRequiredFlagSet ? "c" : "-"
let t = flags.isTransientConnectionFlagSet ? "t" : "-"
let i = flags.isInterventionRequiredFlagSet ? "i" : "-"
let C = flags.isConnectionOnTrafficFlagSet ? "C" : "-"
let D = flags.isConnectionOnDemandFlagSet ? "D" : "-"
let l = flags.isLocalAddressFlagSet ? "l" : "-"
let d = flags.isDirectFlagSet ? "d" : "-"
return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
}
}
fileprivate extension Reachability {
func setReachabilityFlags() throws {
try reachabilitySerialQueue.sync { [unowned self] in
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) {
self.stopNotifier()
throw ReachabilityError.UnableToGetInitialFlags
}
self.flags = flags
}
}
func reachabilityChanged() {
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object: self)
}
}
}
extension SCNetworkReachabilityFlags {
typealias Connection = Reachability.Connection
var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
#if targetEnvironment(simulator)
return .wifi
#else
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
connection = .cellular
}
return connection
#endif
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
}
import Foundation
// MARK : Declare API request type
enum RequestMethod: String {
case get = "GET"
case post = "POST"
case put = "PUT"
case delete = "DELETE"
}

Resources