Swift appended items are not saved - arrays

Here, I declare myArray.
class AcikIlanlarViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myArray: [String] = []
Here, I call the function loadPage which modifies the array.
override func viewDidLoad() {
loadPage()
//when printed here myArray is nil
...
func loadPage() {
...
Alamofire.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default)
.validate { request, response, data in
...
let databases = try JSONDecoder().decode(responseData.self,from: json)
...
for i in 0...databases.orders.count-1 {
myArray.append(databases.orders[i].header!)
}
// when printed here I see the append has worked and myArray is not empty
}
As explained in comments, in viewDidLoad I call loadPage that appends certain stuff in myArray. Just after the append, I can see appended items. However, in viewDidLoad, just after the call to loadPage, myArray turns out to be empty. Why it is not saved?

Reload the table after the for loop
for i in 0...databases.orders.count-1 {
myArray.append(databases.orders[i].header!)
}
self.tableView.reloadData()

loadPage() calls an asynchronous method, so the func will finish before the operation is completed. Mostly, funcs that call async methods should have a completion handler…
override func viewDidLoad() {
loadPage {
self.tableView.reloadData()
}
}
func loadPage(completion: () -> Void) {
Alamofire.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default).validate { request, response, data in
let databases = try JSONDecoder().decode(responseData.self,from: json)
for i in 0...databases.orders.count-1 {
myArray.append(databases.orders[i].header!)
}
completion()
}
}

Related

Swift - Can't use the object that initialized in closure

as a newbie I got a problem.
This is my custom model for API that I use which is called Poke API.
import UIKit
struct Pokemon: Codable {
var results: [PokemonEntry]
}
struct PokemonEntry: Codable {
var name: String
var url: String
}
And this is the service that I use to get data from API:
import Foundation
class Webservice {
func getData(completion: #escaping (Pokemon?, Error?) -> () ) {
guard let url = URL(string: "https://pokeapi.co/api/v2/pokemon?limit151") else {return}
URLSession.shared.dataTask(with: url) { data, res, err in
if let err = err {
completion(nil, err)
return
}
do {
let pokemons = try JSONDecoder().decode(Pokemon.self, from: data!)
completion(pokemons, nil)
// pokemons.results.forEach({print($0.name)})
} catch {
completion(nil, error)
print(error.localizedDescription)
}
}.resume()
}
}
So in my viewController, I wanna get the pokemon object that returned from Webservice().getData function so I can use wherever I want but it comes as a nil, I can use it only inside of Webservice function's closure.
import UIKit
class ViewController: UIViewController {
var pokeList: Pokemon?
override func viewDidLoad() {
super.viewDidLoad()
Webservice().getData { pokemonResponse, error in
if let error = error {
print(error.localizedDescription)
}
self.pokeList = pokemonResponse
print("I can use pokeList here: \(self.pokeList?.results)")
}
print("I cant use pokeList out of Webservice closure, its nil: \(print(pokeList?.results))")
}
}
Try this instead:
class ViewController: UIViewController {
var pokeList: Pokemon? {
didSet {
print("I can use pokeList out of the Webservice closure, it is: \(pokeList?.results ?? "<nil>")")
}
}
override func viewDidLoad() {
super.viewDidLoad()
Webservice().getData { pokemonResponse, error in
if let error = error {
print(error.localizedDescription)
}
self.pokeList = pokemonResponse
print("I can use pokeList here: \(self.pokeList?.results)")
}
}
}
The problem was that you were using pokeList before it got filled by the web service. It worked as follows:
Web service task gets started (waits for a response asynchronously)
Either response is received or your print outside of the block is called which already wants to use what gets filled in the block. The print is usually faster which results in the bug (also known as a race condition)

Could not get JSONArray in variable Swift

So basically I want to make a TableList from my REST service. The REST service can be decoded by this code block:
func getAllParkeergarages(_ completion: #escaping ([Parkeergarage]) -> ()) {
if let url = URL(string: "http://localhost:8080/parkeergarages") {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
do {
let res = try JSONDecoder().decode([Parkeergarage].self, from: data)
print(res)
completion(res)
return
} catch let error {
print(error)
}
}
}.resume()
}
}
By using this codeblock I can print the whole JSON in my terminal:
getAllParkeergarages { (array) in
print(array)
}
To get the data in a TableView I need to have the data in a variable. But here is where I get stuck. I tried some different methodes like:
private var data: [Parkeergarage] = getAllParkeergarages { (array) in
return array
}
but is gives me an error: 'Cannot convert value of type '()' to specified type '[Parkeergarage]'. Can someone help me get the result of the function in the variable?
you should do
private var data: [Parkeergarage] = []
in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
getAllParkeergarages { (array) in
self.data = array
self.tableView.reloadData()
}
}
I cannot explain any more.

Firestore instantiate objects with data recover Swift 5.0

I get all the data from my snapshot and create an object list with the data.
My problem: I can't return a list to use my objects in other code functions.
I tried to browse my list to create using my snapshot to implement a new list of objects declared above in my code.
class ViewController: UIViewController {
lazy var usersCollection = Firestore.firestore().collection("ship")
var ships: [MyShip] = []
override func viewDidLoad() {
super.viewDidLoad()
getUsers()
print(ships.count)
}
The getData function:
func getUsers() {
usersCollection.getDocuments { (snapshot, _) in
//let documents = snapshot!.documents
// try! documents.forEach { document in
//let myUser: MyUser = try document.decoded()
//print(myUser)
//}
let myShip: [MyShip] = try! snapshot!.decoded()
// myShip.forEach({print($0)})
for elt in myShip {
print(elt)
self.ships.append(elt)
}
print(self.ships[1].nlloyds)
}
}
result console
Result in the console:
- my list is not filled return 0
- I print the objects well and I print them well
- I print the ships object[1].nloyds = 555 well in the function
Your print(ships.count) call in viewDidLoad is printing an empty array because the .getDocuments() method is asynchronous. Try writing getUsers as a closure like this:
func getUsers(completion: #escaping ([MyShip]) -> Void) {
usersCollection.getDocuments { (snapshot, _) in
let myShip: [MyShip] = try! snapshot!.decoded()
completion(myShip)
}
}
and then use it in the viewDidLoad method like this:
override func viewDidLoad() {
super.viewDidLoad()
getUsers() { shipsFound in
self.ships = shipsFound
print(self.ships.count)
}
}

Swift 3 - Can not use array made Alamofire request

hoping that someone can help me! Working on this one for a while now. Basically my problem is that I can not use the data in a UItableviewcontroller that is received by an Alamofire request. The request I want to put in a struct in the alamofire request. In the end I can not use the information what is put in the array. Looks like the array keeps empty outside the Function. for that I tried to make a closure, I receive the table in viewDidLoad request, but still can not use it outside that one.
I have a structure in a swift file called Section:
struct Mijnproducten {
var productname : String!
var productdesc : String!
var expanded : Bool!
init(productname: String, productdesc: String, expanded: Bool)
{
self.productname = productname
self.productdesc = productdesc
self.expanded = false
}
}
UitableviewController looks like this:
Array I made:
var mijnproducten01 = [Mijnproducten]()
Below the fund with alamofire request:
func GetUserProperty(completion: #escaping ([Mijnproducten]) -> Void) {
Alamofire.request(URL_USER_PROPERTY, method: .post, encoding: JSONEncoding.default) .responseJSON(completionHandler: { response -> Void in
//getting the json value from the server productid, tagid, status, productimage
switch response.result {
case .success(let value):
let jsonArray = JSON(value)
print(value)
var Mijnproducten01 : [Mijnproducten] = []
for (index, dict) in jsonArray {
let thisObject = Mijnproducten(productname: dict["productname"].string!, productdesc: dict["productdesc"].string!, expanded: false )
Mijnproducten01.append(thisObject) }
completion(Mijnproducten01)
case .failure(let error):
print(error)
completion([])
}
self.tableView.reloadData()
})
}
In the viedDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
GetUserProperty(completion: { data in
self.mijnproducten01 = data
print("yess", self.mijnproducten01)})
print("nooo",mijnproducten01)
}
There is printed information in the yesss print, but not in the nooo.
In the end the goal is to substract information from the array and use it in the tableCell and Header.
When I put this in the header function:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "expandableHeaderView") as! ExpandableHeaderView
header.customInit(Productname: mijnproducten01[Mijnproducten].productname, Productdesc: mijnproducten01[Mijnproducten].productdesc, section: section, delegate: self)
//print("print", mijnproducten01)
return header
}
I get an error in: mijnproducten01[Mijnproducten].productname.
I hope some one can help on the way!
Thanks! I found a solution, maybe not the best way but it works. I added an extra UI label in the rows. That UI label gets assigned the value that is also used in the header. In the end I made the UILabel not visible. In this way I get with every row in a section the wright header description that I can get in didSelectRow!

Get data in array after web request in Swift

I am learning to program in swift. I want to load some data in JSON format (using swiftyJSON and alamoFire) in an array and then use that array in outside the function. When I print the array it is empty and printed before the output of the loop. how can I fill naamArray2 with the content of naamArray
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
var naamArray = [String]()
var naamArray2 = [String]()
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Alamofire.request(.GET, "http://217.149.68.51:8080/xfind.php?userId=mike", parameters: ["foo": "bar"])
.responseJSON
{ response in
if let value = response.result.value
{
print("JSON: \(value)")
let json = JSON(value)
print(json["producten"][0]["productnaam"].stringValue)
let loopCounter = json["producten"].count
for i in 0...loopCounter
{
let tempstring = json["producten"][i]["productnaam"].stringValue
self.naamArray.append(tempstring)
}
print("\(self.naamArray)")
}
}
print("koekkoek")
print("tweede \(self.naamArray)")
naamArray2 = self.naamArray
}
Call request is run async so when you put it at bottom of viewDidload it can't assign when it have value.
you can create function call assignValue and call after request success:
func assignValue() {
naamArray2 = self.naamArray
}
change to:
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Alamofire.request(.GET, "http://217.149.68.51:8080/xfind.php?userId=mike", parameters: ["foo": "bar"])
.responseJSON
{ response in
if let value = response.result.value
{
print("JSON: \(value)")
let json = JSON(value)
print(json["producten"][0]["productnaam"].stringValue)
let loopCounter = json["producten"].count
for i in 0...loopCounter
{
let tempstring = json["producten"][i]["productnaam"].stringValue
self.naamArray.append(tempstring)
}
print("\(self.naamArray)")
assignValue()
}
}
}

Resources