collection view reloading before fetching from api - swift

I have a collection view which reloads once the data is fetched from the api.
I have condition that when a array count is greater than zero,it should reload the collection view.
The code is as given below:
if self.mainarray.count>0
{
self.collectionview1.reloadData()
}
If the mainarray count is 2,then it is reloading the collection view when the count is 1 itself.
How to make it reload only when the full data is fetched?
func getcart() {
print("getcart function",self.token)
let headers: HTTPHeaders = [
"Content-Type":"application/json",
"Authorization":"Bearer "+self.token!
]
AF.request("https:XXXX", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success(let json):
// print("Validation Successful",json)
if let res = json as? [[String: Any]]{
print("res count is",res.count)
self.skuarray.removeAll()
for item in 0..<res.count
{
self.sku = res[item]["name"] as! String
self.skuarray.append(self.sku!)
let qty:Double = res[item]["qty"] as! Double
}
if self.skuarray.count > 0
{
for i in 0..<self.skuarray.count
{
self.getimage(sku:self.skuarray[i])
}
}
}
else
{
self.showAlert(message: "No products in the cart")
}
case let .failure(error):
print(error)
}
}
}
func getimage(sku: String)
{
AF.request("https:XXXXXX" + sku, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
//New
let decoder = JSONDecoder()
do {
let user = try decoder.decode(ProductDetailDataModel.self, from: response.data!)
self.detailmodel = user
// self.orgsearchDataModel = user
DispatchQueue.main.async
{
self.doLabelChange()
print("total images aree",self.mainarray)
if !self.mainarray.isEmpty
{
self.tableview1.reloadData()
}
}
} catch {
print(error.localizedDescription)
}
}
}
func doLabelChange(){
let sku = UserDefaults.standard.set((self.detailmodel?.sku)!, forKey: "sku")
let array = self.detailmodel?.mediaGalleryEntries
print("array is",array)
let image = array![0].file
print("image is ",image)
let imageurl = "https://adamas-intl.com/pub/media/catalog/product/" + image
print("imageurl is",imageurl)
self.mainarray.append(imageurl)
}

Related

How can I access a single value within a JSON array | Swift

Essentially I have the following function execute when a tableview controller loads. Using one of the JSON response values I would like to create a conditional - how can I print the pawprint value where myid == 3 :
I have attempted to access it in DispatchQueue.main.async in the same function but I am confused how to refer to it? for example I cannot do myData.pawprint - because it is a JSON array.
private func fetchJSON() {
guard let url = URL(string: "test.com")
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "mykey=\(keyValue)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { [self] data, _, error in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
self.structure.sort { $0.thisdate > $1. thisdate }
let res = try decoder.decode([thisStructure].self, from: data)
let grouped = Dictionary(grouping: res, by: { $0. thisdate })
_ = grouped.keys.sorted()
sections = grouped.map { thisSections(date: $0.key, items: $0.value) }
.sorted { $0.date > $1.date }
print(sections.map(\.date))
sections.map.
let myData = try JSONDecoder().decode(thisStructure.self, from: data)
DispatchQueue.main.async {
self.tableView.reloadData()
print("TableView Loaded")
}
}
catch {
print(error)
}
}.resume()
}
struct thisSections {
let date : String
var items : [thisStructure]
}
struct thisStructure: Decodable {
let myid: Int
let pawprint: String
let activationid: Int
let stopid: Int
}
Example of JSON response:
[
{
"myid": 3,
"pawprint": "Print Me",
"activationid": 2,
"stopid": 1
}
]
MyData.forEach {
item in
if item.myid == 3{
prin(\(item.pawprint))
}
}
are you looking for this ?
you could try this approach to select, then print the specific thisStructure
pawprint you want:
private func fetchJSON() {
guard let url = URL(string: "test.com")
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "mykey=\(keyValue)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { [self] data, _, error in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
self.structure.sort { $0.thisdate > $1. thisdate }
let res = try decoder.decode([thisStructure].self, from: data)
let grouped = Dictionary(grouping: res, by: { $0. thisdate })
_ = grouped.keys.sorted()
sections = grouped.map { thisSections(date: $0.key, items: $0.value) }
.sorted { $0.date > $1.date }
print(sections.map(\.date))
// --- here res is an array of `thisStructure`
if let selectedOne = res.first(where: {$0.myid == 3}) {
print(selectedOne.pawprint)
}
// do not try to decode this from the data
// let myData = try JSONDecoder().decode(thisStructure.self, from: data)
DispatchQueue.main.async {
self.tableView.reloadData()
print("TableView Loaded")
}
}
catch {
print(error)
}
}.resume()
}

Swift: getting nil when decoding API response

I'm having an issue decoding an API response.
So we have a NetworkManager class which we use to decode APIs. I have a simple GET endpoint that I need to retrieve a list of airports from. Here is the endpoint:
static let airports = Endpoint(url: "/test/airports")
Endpoint is defined as follows:
public struct Endpoint : Equatable {
public init(url: String? = nil, pattern: String? = nil, methods: [Test.HTTPMethod] = [.get], type: Test.EncodingType = .json)
}
Then in our network manager we have:
public func call<R: Decodable>(_ endpoint: Endpoint,
with args: [String: String]? = nil,
using method: HTTPMethod = .get,
expecting response: R.Type?,
completion: APIResponse<R>) {
call(endpoint, with: args, parameters: Nothing(),
using: method, posting: Nothing(), expecting: response, completion: completion)
}
My Airport model is as follows:
struct Airport: Codable {
let id: String
let name: String
let iata3: String
let icao4: String
let countryCode: String
}
And then I'm calling the endpoint like:
private func getAirportsList() {
API.client.call(.airports, expecting: [Airport].self) { (result, airports) in
print(airports)
}
}
Now I'm using Charles to proxy and I am getting the response I expect:
[{
"id": "5f92b0269c983567fc4b9683",
"name": "Amsterdam Schiphol",
"iata3": "AMS",
"icao4": "EHAM",
"countryCode": "NL"
}, {
"id": "5f92b0269c983567fc4b9685",
"name": "Bahrain International",
"iata3": "BAH",
"icao4": "OBBI",
"countryCode": "BH"
}, {
"id": "5f92b0269c983567fc4b968b",
"name": "Bankstown",
"iata3": "BWU",
"icao4": "YSBK",
"countryCode": "AU"
}]
But in my getAirports() method, airports is nil. I'm really struggling to see why. Clearly the endpoint is being hit correctly but my decoding is failing.
Edit:
Full method:
private func call<P: Encodable, B: Encodable, R: Decodable>(_ endpoint: Endpoint,
with args: [String: String]? = nil,
parameters params: P?,
using method: HTTPMethod = .get,
posting body: B?,
expecting responseType: R.Type?,
completion: APIResponse<R>) {
// Prepare our URL components
guard var urlComponents = URLComponents(string: baseURL.absoluteString) else {
completion?(.failure(nil, NetworkError(reason: .invalidURL)), nil)
return
}
guard let endpointPath = endpoint.url(with: args) else {
completion?(.failure(nil, NetworkError(reason: .invalidURL)), nil)
return
}
urlComponents.path = urlComponents.path.appending(endpointPath)
// Apply our parameters
applyParameters: if let parameters = try? params.asDictionary() {
if parameters.count == 0 {
break applyParameters
}
var queryItems = [URLQueryItem]()
for (key, value) in parameters {
if let value = value as? String {
let queryItem = URLQueryItem(name: key, value: value)
queryItems.append(queryItem)
}
}
urlComponents.queryItems = queryItems
}
// Try to build the URL, bad request if we can't
guard let urlString = urlComponents.url?.absoluteString.removingPercentEncoding,
var url = URL(string: urlString) else {
completion?(.failure(nil, NetworkError(reason: .invalidURL)), nil)
return
}
if let uuid = UIDevice.current.identifierForVendor?.uuidString, endpoint.pattern == "/logging/v1/device/<device_id>" {
let us = "http://192.168.6.128:3000/logging/v1/device/\(uuid)"
guard let u = URL(string: us) else { return }
url = u
}
// Can we call this method on this endpoint? If not, lets not try to continue
guard endpoint.httpMethods.contains(method) else {
completion?(.failure(nil, NetworkError(reason: .methodNotAllowed)), nil)
return
}
// Apply debug cookie
if let debugCookie = debugCookie {
HTTPCookieStorage.shared.setCookies(
HTTPCookie.cookies(
withResponseHeaderFields: ["Set-Cookie": debugCookie],
for:url
), for: url, mainDocumentURL: url)
}
// Build our request
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
if let headers = headers {
for (key, value) in headers {
request.setValue(value, forHTTPHeaderField: key)
}
}
// If we are posting, safely retrieve the body and try to assign it to our request
if !(body is NothingProtocol) {
guard let body = body else {
completion?(.failure(nil, NetworkError(reason: .buildingPayload)), nil)
return
}
do {
let result = try encode(body: body, type: endpoint.encodingType)
request.httpBody = result.data
request.setValue(result.headerValue, forHTTPHeaderField: "Content-Type")
} catch {
completion?(.failure(nil, NetworkError(reason: .buildingPayload)), nil)
return
}
}
// Build our response handler
let task = session.dataTask(with: request as URLRequest) { (rawData, response, error) in
// Print some logs to help track requests
var debugOutput = "URL\n\(url)\n\n"
if !(params is Nothing.Type) {
debugOutput.append(contentsOf: "PARAMETERS\n\(params.asJSONString() ?? "No Parameters")\n\n")
}
if !(body is Nothing.Type) {
debugOutput.append(contentsOf: "BODY\n\(body.asJSONString() ?? "No Body")\n\n")
}
if let responseData = rawData {
debugOutput.append(contentsOf: "RESPONSE\n\(String(data: responseData, encoding: .utf8) ?? "No Response Content")")
}
Logging.client.record(debugOutput, domain: .network, level: .debug)
guard let httpResponse = response as? HTTPURLResponse else {
guard error == nil else {
completion?(.failure(nil, NetworkError(reason: .unwrappingResponse)), nil)
return
}
completion?(.failure(nil, NetworkError(reason: .invalidResponseType)), nil)
return
}
let statusCode = httpResponse.statusCode
// We have an error, return it
guard error == nil, NetworkManager.successStatusRange.contains(statusCode) else {
var output: Any?
if let data = rawData {
output = (try? JSONSerialization.jsonObject(with: data,
options: .allowFragments)) ?? "Unable to connect"
Logging.client.record("Response: \(String(data: data, encoding: .utf8) ?? "No error data")", domain: .network)
}
completion?(.failure(statusCode, NetworkError(reason: .requestFailed, json: output)), nil)
return
}
// Safely cast the responseType we are expecting
guard let responseType = responseType else {
completion?(.failure(statusCode, NetworkError(reason: .castingToExpectedType)), nil)
return
}
// If we are expecting nothing, return now (since we will have nothing!)
if responseType is Nothing.Type {
completion?(.success(statusCode), nil)
return
}
guard let data = rawData else {
assertionFailure("Could not cast data from payload when we passed pre-cast checks")
return
}
// Decode the JSON and cast to our expected response type
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let responseObject = try decoder.decode(responseType, from: data)
completion?(.success(statusCode), responseObject)
return
} catch let error {
let content = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
Logging.client.record("Failed to build codable from JSON: \(String(describing: content))\n\nError: \(error)", domain: .network, level: .error)
assertionFailure("Failed to build codable from JSON: \(error)")
completion?(.failure(statusCode, NetworkError(reason: .castingToExpectedType)), nil)
return
}
}
// Submit our request
task.resume()
}

Call request by request Alamofire swift

I wonder how I could make the request executed one by one. It's about image processing. And the server cannot process more than one image. The problem is that I need to send 10 pictures at a time, and if I send everything at once, I have a problem with the timeout, and now I'm interested in how to send the next request when response from the previous one arrives?
func clearingImage() {
if clearingImageArray.count < 0 || indexOfClearImage >= clearingImageArray.count
{
guard let imageName = ImageFilenameUtilities.getNameOfImageFromPath(filePath: clearingImageArray[indexOfClearImage]) else
{
indexOfClearImage+=1
clearingImage()
return
}
guard let clearType = ImageFilenameUtilities.getClearTypeFromFilename(filename: imageName) else
{
indexOfClearImage+=1
clearingImage()
return
}
guard let image = gallery?.getImageForPath(path: clearingImageArray[indexOfClearImage]) else
{
indexOfClearImage+=1
clearingImage()
return
}
sendImageToServer(image: image, imageName: imageName)
}
}
func sendImageToServer(image:UIImage,imageName:String)
{
let url = "example.com"
let headers : HTTPHeaders = [
"Connection": "Keep-Alive"
// "Content-Type": "application/x-www-form-urlencoded"
]
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 12000
manager.session.configuration.timeoutIntervalForResource = 12000
manager.upload(multipartFormData: { multipleData in
for (key, value) in parameter {
multipleData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
multipleData.append(
imageData, withName: "image", fileName: imageName, mimeType: "image/jpg")}, to: url, method: .post, headers: headers){
(result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
self.indexOfClearImage += 1
if let image = UIImage(data: response.data!) {
//save image to galery
}
else
{
if let error = response.result.error {
if error._code == NSURLErrorTimedOut {
self.indexOfClearImage -= 1
}
}
}
}
case .failure(let encodingError):
//send next image to server
self.indexOfClearImage += 1
}
}
self.clearingImage()
}
Just send the 2nd request on the 1st completion block, when you get the response, and so on.
func firstRequest() {
AF.request("url/here").response { response in
self.secondRequest()
}
}
func secondRequest() {
AF.request("url/here").response { response in
// call 3rd request and so on...
}
}

unable to load JSON data in 'data' array

when I call this function the array 'data' is showing empty square brackets, it is not giving me any errors though
here is the code :-
import Foundation
import Alamofire
import SwiftyJSON
class Networking {
var data = [Item]()
let tVC = TableViewController()
let url = "https://api.coinmarketcap.com/v1/ticker/"
func getCoinData(url: String) {
Alamofire.request(url, method: .get)
.responseJSON { response in
if response.result.isSuccess {
let coinJSON : JSON = JSON(response.result.value!)
for i in 0..<coinJSON.count{
let coinName = Item(bitJSON: coinJSON[i])
self.data.append(coinName)
self.tVC.tableView.reloadData()
}
}
else {
print("Error: \(String(describing: response.result.error))")
}
}
}
}
Try this one.
Change your url, method is "Get" and your mapping model.
public static func getArrayInformation(completionHandler: #escaping (APIResponse) -> Void) {
let url = "your url"
let params: Parameters = ["username": "admin",
"password": "1234"]
Alamofire.request(url,
method: .post,
parameters: params,
encoding: JSONEncoding.default,
headers: ["Content-Type": "application/json"])
.responseDecodableObject(keyPath: nil, decoder: JSONDecoder(), completionHandler: { (handler: DataResponse<[Your Object Array]>) in
completionHandler(handler.result.value ?? [Your Object Array]())
})
}
why you reload Table every loop iteration , and instead Loop use Map
class Networking {
var data = [Item]()
let tVC = TableViewController()
let url = "https://api.coinmarketcap.com/v1/ticker/"
func getCoinData(url: String) {
Alamofire.request(url, method: .get)
.responseJSON { response in
if response.result.isSuccess {
let coinJSON : JSON = JSON(response.result.value!)
data = coinJSON.map({ (coinJson) -> Item in
return Item(bitJSON: coinJson)
})
DispatchQueue.main.async {
self.tVC.tableView.reloadData()
}
}
else {
print("Error: \(String(describing: response.result.error))")
}
}
}
}

Alamofire Post Request is not Executed

I'm making a POST Request to my API. All of a sudden the request is being skipped. I have tried to debug into it, but until now without success.
This is my request:
#IBAction func checkLogin(_ sender: Any) {
guard let managedContext = self.managedObjectContext else { return }
let user = NSEntityDescription.insertNewObject(forEntityName: User.identifier, into: managedContext) as! User
let url = ""
let parameters: Parameters =
["username" : usernameTextField.text!, "password" : passwordTextField.text!]
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default).responseJSON { (responseData) -> Void in
let results = JSON(responseData.result.value!)
print(results)
user.firstName = results["firstname"].string!
let responseString : String = responseData.response?.allHeaderFields["Set-Cookie"] as! String
if let range = responseString.range(of: ";"){
let startIndex = (responseString.range(of: "="))
let cookie = responseString[(startIndex?.upperBound)!...range.lowerBound]
user.setValue(cookie, forKey: "token")
}
} do {
try self.dataController.saveContext()
}catch {
print("Save Error User")
}
I'm Using Alamofire 4.5 with Swift 3.1.
Please use different types of data request handling block and check again.
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default)
.responseJSON { response in
print("JSON Response")
}
.responseData { response in
print("Data Response")
}
.responseString { response in
print("String Response")
}
.responsePropertyList { response in
print("PropertyList Response")
}