Get full URL from short URL in Swift on iOS - ios

Given a short URL https://itun.es/us/JB7h_, How do you expand it into the full URL? e.g. https://music.apple.com/us/album/blackstar/1059043043

Extension
extension URL {
func getExpandedURL() async throws -> Result<URL, Error> {
var request = URLRequest(url: self)
request.httpMethod = "HEAD"
let (_, response) = try await URLSession.shared.data(for: request)
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
throw URLError.unableToExpand
}
if let expandedURL = response.url {
return .success(expandedURL)
} else {
throw URLError.unableToExpand
}
}
enum URLError: Error {
case unableToExpand
}
}
Crude Demo
struct ContentView: View {
let shortURL = URL(string: "https://itun.es/us/JB7h_")
#State var expandedURLResult: Result<URL, Error>?
var body: some View {
Form {
Section("Short URL") {
Text(shortURL?.description ?? "")
}
Section("Long URL") {
switch expandedURLResult {
case .some(.success(let expandedURL)):
Text(expandedURL.description)
case .none:
Text("Waiting")
case .some(.failure(let error)):
Text(error.localizedDescription)
}
}
}
.task {
do {
expandedURLResult = try await shortURL?.getExpandedURL()
} catch {
expandedURLResult = .failure(error)
}
}
}
}

The final resolved URL will be returned to you in the NSURLResponse: response.URL.
You should also make sure to use the HTTP HEAD method to avoid downloading unnecessary data (since you don't care about the resource body).
Swift 4.2 Updated :
extension URL {
func resolveWithCompletionHandler(completion: #escaping (URL) -> Void) {
let originalURL = self
var req = URLRequest(url: originalURL)
req.httpMethod = "HEAD"
URLSession.shared.dataTask(with: req) { body, response, error in
completion(response?.url ?? originalURL)
}.resume()
}
Older Swift Versions:
extension NSURL
{
func resolveWithCompletionHandler(completion: NSURL -> Void)
{
let originalURL = self
let req = NSMutableURLRequest(URL: originalURL)
req.HTTPMethod = "HEAD"
NSURLSession.sharedSession().dataTaskWithRequest(req) { body, response, error in
completion(response?.URL ?? originalURL)
}.resume()
}
}
// Example:
NSURL(string: "https://itun.es/us/JB7h_")!.resolveWithCompletionHandler {
print("resolved to \($0)") // prints https://itunes.apple.com/us/album/blackstar/id1059043043
}

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()
}

Swift 5, RxSwift: Network request with RxSwift

I am starting to use RxSwift to make the service call.
This was my old code:
class Service: GraphQLService {
func graphQL(body: [String: Any?], onSuccess: #escaping (Foundation.Data) throws -> (), onFailure: #escaping (Error) -> ()) {
guard let urlValue = Bundle.main.urlValue else { return }
guard let url = URL(string: urlValue) else { return
print("Error with info.plist")
}
var request = URLRequest(url: url)
let userKey = Bundle.main.userKeyValue
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(userKey, forHTTPHeaderField: "userid")
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
onFailure(error)
}
if let data = data {
do{
try onSuccess(data)
}
catch{
onFailure(error)
}
}
}.resume()
}
And here I do the function to get time deposits:
final class TimeDepositManager: Service, TimeDepositManagerProtocol {
let timeDepositQuery = Bundle.main.queryValue
func getTimeDeposits(onSuccess: #escaping ([TimeDeposits]) -> (), onFailure: #escaping (Error) -> ()) {
let body = ["query": timeDepositQuery]
Service().graphQL(body: body, onSuccess: { data in
let json = try? JSONDecoder().decode(GraphQLResponse.self, from: data)
onSuccess(json?.data?.account?.timeDeposits ?? [])
}, onFailure: onFailure)
}
And so far this is my code with RxSwift:
class Service: GraphQLService {
func graphQL(body: [String : Any?]) -> Observable<Foundation.Data> {
return Observable.create { observer in
let urlValue = Bundle.main.urlValue
let url = URL(string: urlValue ?? "")
let session = URLSession.shared
var request = URLRequest(url: url!)
let userKey = Bundle.main.userKeyValue
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(userKey, forHTTPHeaderField: "userid")
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
session.dataTask(with: request) { (data, response, error) in
if let error = error {
observer.onError(error)
}
if let data = data {
do{
try onSuccess(data)
observer.onNext(data)
}
catch{
//onFailure(error)
observer.onError(error)
print("Error: \(error.localizedDescription)")
}
}
}.resume()
return Disposables.create {
session.finishTasksAndInvalidate()
}
}
}
This is where I don't understand how in my getTimeDeposits () I can do the deserialization with try? JSONDecoder () ... with RxSwift without using onSuccess?
final class TimeDepositManager: Service, TimeDepositManagerProtocol {
let timeDepositQuery = Bundle.main.queryValue
func getTimeDeposits() -> Observable<[TimeDeposits]> {
let body = ["query": timeDepositQuery]
Service().graphQL(body: body)
}
You can have getTimeDeposits() return an Observable as well and handle the deserialization in a map closure. A couple of other things.
RxCocoa already has a method on URLSession so you don't need to write your own.
I suggest reducing the amount of code you have in a function that makes the network request. You want to be able to test your logic for making the request without actually making it.
Something like this:
final class TimeDepositManager: Service, TimeDepositManagerProtocol {
let timeDepositQuery = Bundle.main.queryValue
func getTimeDeposits() -> Observable<[TimeDeposits]> {
let body = ["query": timeDepositQuery]
return Service().graphQL(body: body)
.map { try JSONDecoder().decode(GraphQLResponse.self, from: $0).data?.account?.timeDeposits ?? [] }
}
}
class Service: GraphQLService {
func graphQL(body: [String: Any?]) -> Observable<Data> {
guard let urlValue = Bundle.main.urlValue else { fatalError("Error with info.plist") }
let request = urlRequest(urlValue: urlValue, body: body)
return URLSession.shared.rx.data(request: request) // this is in RxCocoa
}
func urlRequest(urlValue: String, body: [String: Any?]) -> URLRequest {
guard let url = URL(string: urlValue) else { fatalError("Error with urlValue") }
var request = URLRequest(url: url)
let userKey = Bundle.main.userKeyValue
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(userKey, forHTTPHeaderField: "userid")
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
return request
}
}
If you don't want to use RxCocoa for some reason, here is the correct way to wrap the URLSession.dataTask method:
extension URLSession {
func data(request: URLRequest) -> Observable<Data> {
Observable.create { observer in
let task = self.dataTask(with: request, completionHandler: { data, response, error in
guard let response = response as? HTTPURLResponse else {
observer.onError(URLError.notHTTPResponse(data: data, response: response))
return
}
guard 200 <= response.statusCode && response.statusCode < 300 else {
observer.onError(URLError.failedResponse(data: data, response: response))
return
}
guard let data = data else {
observer.onError(error ?? RxError.unknown)
return
}
observer.onNext(data)
observer.onCompleted() // be sure to call `onCompleted()` when you are done emitting values.
// make sure every possible path through the code calls some method on `observer`.
})
return Disposables.create { task.cancel() } // don't forget to handle cancelation properly. You don't want to kill *all* tasks, just this one.
}
}
}
enum URLError: Error {
case notHTTPResponse(data: Data?, response: URLResponse?)
case failedResponse(data: Data?, response: HTTPURLResponse)
}

FlatMap with Generic ReturnType using Combine

I'm building a network API.
I'm new to Combine and I'm having some troubles with it, I'm trying to chain publish network requests, in this case I'm forming an URLRequest publisher and dispatching it on another publisher, the problem is that I cant make the flatMap work on the second publisher.
First I assemble the URLRequest with the Auth token:
func asURLRequest(baseURL: String) -> AnyPublisher<URLRequest, NetworkRequestError> {
return Deferred {
Future<URLRequest, NetworkRequestError> { promise in
if var urlComponents = URLComponents(string: baseURL) {
urlComponents.path = "\(urlComponents.path)\(path)"
urlComponents.queryItems = queryItemsFrom(params: queryParams)
if let finalURL = urlComponents.url {
if let user = Auth.auth().currentUser {
print("##### final url -> \(finalURL)")
// Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
user.getIDToken(completion: { (token, error) in
if let fbToken = token {
var request = URLRequest(url: finalURL)
request.httpMethod = method.rawValue
request.httpBody = requestBodyFrom(params: body)
let defaultHeaders: HTTPHeaders = [
HTTPHeaderField.contentType.rawValue: contentType.rawValue,
HTTPHeaderField.acceptType.rawValue: contentType.rawValue,
HTTPHeaderField.authentication.rawValue: fbToken
]
request.allHTTPHeaderFields = defaultHeaders.merging(headers ?? [:], uniquingKeysWith: { (first, _) in first })
print("##### API TOKEN() SUCCESS: \(defaultHeaders)")
promise(.success(request))
}
if let fbError = error {
print("##### API TOKEN() ERROR: \(fbError)")
promise(.failure(NetworkRequestError.decodingError))
}
})
}
} else {
promise(.failure(NetworkRequestError.decodingError))
}
} else {
promise(.failure(NetworkRequestError.decodingError))
}
}
}.eraseToAnyPublisher()
}
Then I'm trying to dispatch a request (publisher) and return another publisher, the problem is that the .flatMap is not getting called:
struct APIClient {
var baseURL: String!
var networkDispatcher: NetworkDispatcher!
init(baseURL: String,
networkDispatcher: NetworkDispatcher = NetworkDispatcher()) {
self.baseURL = baseURL
self.networkDispatcher = networkDispatcher
}
/// Dispatches a Request and returns a publisher
/// - Parameter request: Request to Dispatch
/// - Returns: A publisher containing decoded data or an error
func dispatch<R: Request>(_ request: R) -> AnyPublisher<R.ReturnType, NetworkRequestError> {
print("##### --------> \(request)")
//typealias RequestPublisher = AnyPublisher<R.ReturnType, NetworkRequestError>
return request.asURLRequest(baseURL: baseURL)
.flatMap { request in
//NOT GETTING CALLED
self.networkDispatcher.dispatch(request: request)
}.eraseToAnyPublisher()
}
The final publisher that is not being called is the following:
struct NetworkDispatcher {
let urlSession: URLSession!
public init(urlSession: URLSession = .shared) {
self.urlSession = urlSession
}
/// Dispatches an URLRequest and returns a publisher
/// - Parameter request: URLRequest
/// - Returns: A publisher with the provided decoded data or an error
func dispatch<ReturnType: Codable>(request: URLRequest) -> AnyPublisher<ReturnType, NetworkRequestError> {
return urlSession
.dataTaskPublisher(for: request)
// Map on Request response
.tryMap({ data, response in
// If the response is invalid, throw an error
if let response = response as? HTTPURLResponse,
!(200...299).contains(response.statusCode) {
throw httpError(response.statusCode)
}
// Return Response data
return data
})
// Decode data using our ReturnType
.decode(type: ReturnType.self, decoder: JSONDecoder())
// Handle any decoding errors
.mapError { error in
handleError(error)
}
// And finally, expose our publisher
.eraseToAnyPublisher()
}
}
Running the code:
struct ReadUser: Request {
typealias ReturnType = UserData
var path: String
var method: HTTPMethod = .get
init(_ id: String) {
path = "users/\(id)"
}
}
let apiClient = APIClient(baseURL: BASE_URL)
var cancellables = [AnyCancellable]()
apiClient.dispatch(ReadUser(Auth.auth().currentUser?.uid ?? ""))
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { result in
switch result {
case .failure(let error):
// Handle API response errors here (WKNetworkRequestError)
print("##### Error loading data: \(error)")
default: break
}
},
receiveValue: { value in
})
.store(in: &cancellables)
I took your code and boiled it down to just the Combine parts. I could not reproduce the issue you are describing. I'll post that code below. I recommend you start simplifying your code a bit at a time to see if that helps. Factoring out the Auth and Facebook token code seems like a good candidate to start with. Another good debugging technique might be to put in more explicit type declarations to make sure your closures are taking and returning what you expect. (just the other day I had a map that I thought I was applying to an Array when I was really mapping over Optional).
Here's the playground:
import UIKit
import Combine
func asURLRequest(baseURL: String) -> AnyPublisher<URLRequest, Error> {
return Deferred {
Future<URLRequest, Error> { promise in
promise(.success(URLRequest(url: URL(string: "https://www.apple.com")!)))
}
}.eraseToAnyPublisher()
}
struct APIClient {
var networkDispatcher: NetworkDispatcher!
init(networkDispatcher: NetworkDispatcher = NetworkDispatcher()) {
self.networkDispatcher = networkDispatcher
}
func dispatch() -> AnyPublisher<Data, Error> {
return asURLRequest(baseURL: "Boo!")
.flatMap { (request: URLRequest) -> AnyPublisher<Data, Error> in
print("Request Received. \(String(describing: request))")
return self.networkDispatcher.dispatch(request: request)
}.eraseToAnyPublisher()
}
}
func httpError(_ code: Int) -> Error {
return NSError(domain: "Bad Things", code: -1, userInfo: nil)
}
func handleError(_ error: Error) -> Error {
debugPrint(error)
return error
}
struct NetworkDispatcher {
let urlSession: URLSession!
public init(urlSession: URLSession = .shared) {
self.urlSession = urlSession
}
func dispatch(request: URLRequest) -> AnyPublisher<Data, Error> {
return urlSession
.dataTaskPublisher(for: request)
.tryMap({ data, response in
if let response = response as? HTTPURLResponse,
!(200...299).contains(response.statusCode) {
throw httpError(response.statusCode)
}
// Return Response data
return data
})
.mapError { error in
handleError(error)
}
.eraseToAnyPublisher()
}
}
let apiClient = APIClient()
var cancellables = [AnyCancellable]()
apiClient.dispatch()
.print()
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { result in
debugPrint(result)
switch result {
case .failure(let error):
// Handle API response errors here (WKNetworkRequestError)
print("##### Error loading data: \(error)")
default: break
}
},
receiveValue: { value in
debugPrint(value)
})
.store(in: &cancellables)
I refactored your code. Breaking down the offending method into several functions. I could not find any problem. Below is my refactoring. You will notice that I broke all the code that constructs things into their own functions so they can be easily tested without dealing with the effect (I don't even have to mock the effect to test the logic.)
extension Request {
func asURLRequest(baseURL: String) -> AnyPublisher<URLRequest, NetworkRequestError> {
guard let user = Auth.auth().currentUser else {
return Fail(error: NetworkRequestError.missingUser)
.eraseToAnyPublisher()
}
return user.idTokenPublisher()
.catch { error in
Fail(error: NetworkRequestError.badToken(error))
}
.tryMap { token in
makeRequest(
finalURL: try finalURL(baseURL: baseURL),
fbToken: token
)
}
.eraseToAnyPublisher()
}
func finalURL(baseURL: String) throws -> URL {
guard var urlComponents = URLComponents(string: baseURL) else {
throw NetworkRequestError.malformedURLComponents
}
urlComponents.path = "\(urlComponents.path)\(path)"
urlComponents.queryItems = queryItemsFrom(params: queryParams)
guard let result = urlComponents.url else {
throw NetworkRequestError.malformedURLComponents
}
return result
}
func makeRequest(finalURL: URL, fbToken: String) -> URLRequest {
var request = URLRequest(url: finalURL)
request.httpMethod = method.rawValue
request.httpBody = requestBodyFrom(params: body)
let defaultHeaders: HTTPHeaders = [
HTTPHeaderField.contentType.rawValue: contentType.rawValue,
HTTPHeaderField.acceptType.rawValue: contentType.rawValue,
HTTPHeaderField.authentication.rawValue: fbToken
]
request.allHTTPHeaderFields = defaultHeaders.merging(
headers ?? [:],
uniquingKeysWith: { (first, _) in first }
)
return request
}
}
extension User {
func idTokenPublisher() -> AnyPublisher<String, Error> {
Deferred {
Future { promise in
getIDToken(completion: { token, error in
if let token = token {
promise(.success(token))
}
else {
promise(.failure(error ?? UnknownError()))
}
})
}
}
.eraseToAnyPublisher()
}
}
struct UnknownError: Error { }

Alamofire is getting slow on HTTPS but fine in HTTP

In my App multiple Apis . i have 2 differnet server one is for HTTP and one for HTTPS
When i Run my App on Http : it works fine 1st time for each Api and 2 second time for each Api same response time .
But when i run App on https : for each APi first time taking extra time for each Api , then if i hit same Api again it is fast . Problem is why for first time for each APi is slow or taking extra time . But thing is not happened with Android App .
here is My Request builder Class : URLRequestBuilder.swift
import Foundation
import Alamofire
protocol URLRequestBuilder: URLRequestConvertible, APIRequestHandler {
var mainURL: URL { get }
var requestURL: URL { get }
var path: String { get }
var parameters: Parameters? { get }
var method: HTTPMethod { get }
var encoding: ParameterEncoding { get }
var urlRequest: URLRequest { get }
}
extension URLRequestBuilder {
var encoding: ParameterEncoding {
switch method {
case .get:
return URLEncoding.default
default:
return JSONEncoding.default
}
}
var mainURL: URL {
return URL(string: SERVER_URL)!
}
var requestURL: URL {
var fullURL = mainURL.absoluteString + path
if L102Language.currentAppleLanguage() == "ar" && path.contains("?") {
fullURL = fullURL + "&blLocaleCode=ar"
} else if L102Language.currentAppleLanguage() == "ar" {
fullURL = fullURL + "?blLocaleCode=ar"
}
let urlComponents = URLComponents(string: fullURL)!
return urlComponents.url!
}
var urlRequest: URLRequest {
var request = URLRequest(url: requestURL)
request.httpMethod = method.rawValue
if UserDefaults.standard.isUserLoggedIn() {
request.setValue(UserDefaults.standard.getAccessToken(), forHTTPHeaderField: NETWORK_ACCESS_TOKEN)
}
request.setValue(NETWORK_REQUEST_TYPE, forHTTPHeaderField: NETWORK_ACCEPT)
request.setValue(NETWORK_REQUEST_TYPE, forHTTPHeaderField: NETWORK_CONTENT_TYPE)
//request.cachePolicy = .useProtocolCachePolicy
return request
}
func asURLRequest() throws -> URLRequest {
return try encoding.encode(urlRequest, with: parameters)
}
}
final class NetworkClient {
let evaluators = [
"somehttpsURL.com": ServerTrustPolicy.pinCertificates(
certificates: [Certificates.stackExchange],
validateCertificateChain: true,
validateHost: true)
]
let session: SessionManager
// 2
private init() {
session = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: evaluators))
}
// MARK: - Static Definitions
private static let shared = NetworkClient()
static func request(_ convertible: URLRequestConvertible) -> DataRequest {
return shared.session.request(convertible)
}
}
struct Certificates {
static let stackExchange =
Certificates.certificate(filename: "certificate")
private static func certificate(filename: String) -> SecCertificate {
let filePath = Bundle.main.path(forResource: filename, ofType: "der")!
let data = try? Data(contentsOf: URL(fileURLWithPath: filePath))
let certificate = SecCertificateCreateWithData(nil, data! as CFData)!
return certificate
}
}
And my Request Handler Class is :
extension APIRequestHandler where Self : URLRequestBuilder {
// For Response Object
func send<T: AnyObject>(modelType: T.Type, data: [UIImage]? = nil, success: #escaping ( _ servicResponse: AnyObject) -> Void, fail: #escaping ( _ error: NSError) -> Void, showHUD: Bool) where T: Mappable {
if let data = data {
uploadToServerWith(modelType: modelType, images: data, request: self, parameters: self.parameters, success: success, fail: fail)
} else {
//print(requestURL.absoluteString)
// NetworkClient.
request(self).authenticate(user: APIAuthencationUserName, password: APIAuthencationPassword).validate().responseObject { (response: DataResponse<T>) in
switch response.result {
case .success(let objectData):
success(objectData)
break
case .failure(let error):
print(error.localizedDescription)
if error.localizedDescription == RefreshTokenFailed {
self.getAccessTokenAPI(completion: { (value) in
if value == TOKEN_SAVED {
self.send(modelType: modelType, success: success, fail: fail, showHUD: showHUD)
return
}else {
fail(error as NSError)
}
})
} else {
fail(error as NSError)
}
}
}
}
}
}

Keep getting the error “Expected to decode Array<Any> but found a dictionary | Swift

I have the following JSON that is formatted like this:
{
"error":false
}
I understand that is not an array because it does not include square brackets on both sides, but I cannot seem to understand how to properly get Swift to interpret this correctly.
This is the structure I am using:
struct CheckStruct: Decodable {
let error: String?
}
And the following is the function that should read the JSON:
private func JSONFunc() {
guard let url = URL(string: "https://example.com/example/example.php"),
let value = name.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "number=\(number)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data else { return }
do {
self.CheckRecord = try JSONDecoder().decode(Array<CheckStruct>.self,from:data)
DispatchQueue.main.async {
// Do something
}
}
catch {
print(error)
}
}.resume()
}
UPDATE:
If I were to use the results of the function to create an if else statement, how would this look?
For example if results are true do this..
else do this...
Your model should be like this:
struct CheckStruct: Codable {
let error: Bool?
}
And your function should be like this:
private func JSONFunc() {
guard let url = URL(string: "https://example.com/example/example.php"),
let value = name.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "number=\(number)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
do {
let myData= try JSONDecoder().decode(CheckStruct.self, from:data)
print(myData.error)
} catch {
print(error)
}
}.resume()
}
BONUS
//Create Typealias
typealias BoolHandler = ((Bool?) -> Void)
//Create Function with Completion
private func fetchData(_ completion: #escaping BoolHandler) {
guard let url = URL(string: "https://example.com/example/example.php"),
let value = name.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "number=\(number)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
do {
let myData= try JSONDecoder().decode(CheckStruct.self, from:data)
DispatchQueue.main.async {
completion(myData.error)
}
} catch {
DispatchQueue.main.async {
completion(nil)
}
}
}.resume()
}
//Call Method
fetchData { isSuccess in
if isSuccess {
// Do something
} else {
// Do something
}
}
I hope it will work for you.
Enjoy.

Resources