Firestore instantiate objects with data recover Swift 5.0 - arrays

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

Related

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.

Swift appended items are not saved

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

AVAudioPlayer using array to queue audio files - Swift

I am looking for a way to simply play audio files one after another.
AVAudioPlayer using an array seems to be the best solution. In fact, I was able to play the first element of the array using Sneak's recommendations found on this page : Here.
But I don't understand where and how to write the second call to AVAudioPlayer in order to play the second file?
The "audioPlayerDidFinishPlaying" function is not reacting. Why?
Thanks for watching.
import Cocoa
import AVFoundation
var action = AVAudioPlayer()
let path = Bundle.main.path(forResource: "test.aif", ofType:nil)!
let url = URL(fileURLWithPath: path)
let path2 = Bundle.main.path(forResource: "test2.aif", ofType:nil)!
let url2 = URL(fileURLWithPath: path2)
let array1 = NSMutableArray(array: [url, url2])
class ViewController: NSViewController
{
#IBOutlet weak var LanceStop: NSButton!
override func viewDidLoad()
{
super.viewDidLoad()
do
{
action = try AVAudioPlayer(contentsOf: array1[0] as! URL)
action.numberOfLoops = 0
action.prepareToPlay()
action.volume = 1
}catch{print("error")}
}
...
#IBAction func Lancer(_ sender: NSButton)
{
if action.isPlaying == true
{
action.stop()
action.currentTime = 0.0
LanceStop.title = "Lancer"
}
else
{
action.play()
LanceStop.title = "Stopper"
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
{
if flag == true
{
LanceStop.title = "Lancer"
}
}
}
But I don't understand where and how to write the second call to
AVAudioPlayer in order to play the second file?
So in order to play the second file, you need to write one method where you will need to initialize the audioplayer and invoke the same method inside audioplayer delegate method audioPlayerDidFinishPlaying like this:-
func playAudioFile(_ index: Int) {
do
{
action = try AVAudioPlayer(contentsOf: array1[index] as! URL)
action.numberOfLoops = 0
action.prepareToPlay()
action.volume = 1
} catch{print("error")
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
//This delegate method will called once it finished playing audio file.
//Here you can invoke your second file. You can declare counter variable
//and increment it based on your file and stop playing your file acordingly.
counter = counter + 1
playAudioFile(counter)
}
Note:- Set Audioplayer delegate to your ViewController in order to get invoke
audioPlayerDidFinishPlaying method like this.
action.delegate = self
Changed Code...
class ViewController: NSViewController, AVAudioPlayerDelegate
{
#IBOutlet weak var LanceStop: NSButton!
override func viewDidLoad()
{
super.viewDidLoad()
}
override var representedObject: Any?
{
didSet
{
// Update the view, if already loaded.
}
}
func playAudioFile(_ index: Int)
{
do
{
action = try AVAudioPlayer(contentsOf: array1[index] as! URL)
action.delegate = self
action.numberOfLoops = 0
action.prepareToPlay()
action.volume = 1
action.play()
}
catch{print("error")}
}
#IBAction func Lancer(_ sender: NSButton)
{
playAudioFile(0)
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
{
if flag == true
{
playAudioFile(1)
}
}
}

How do i refresh a TableView after some data will changed?

I want to change the list of users in only one class, called Network. And i don't understand how to make a TableView update after the userList has changed. I'll show you an example and detailed question in code below.
// Network.swift
class Network {
var userList: [User] = []
// Next functions may change userList array
// For example, the data came from the server, and update the userList with new data
}
// App delegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var network: Network = Network()
..
}
// File TableViewController.swift
class TableViewController: UITableViewController {
…
var userList: [User] = [] // Here I want to have a full copy of the array from Network class
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
self.userList = appDelegate.network.userList // Just copy an array
// And I want that after each update appDelegate.network.userList I updated the table, how to do it better?
self.tableView.reloadData()
}
}
As #JDM mentioned in comment your architecture is messed.
Try to do this delegation using protocols:
// Network.swift
protocol UsersUpdatedProtocol {
func usersListUpdated(list: [User])
}
class Network {
var userList: [User] = [] {
didSet {
delegate?.usersListUpdated(list: userList)
}
}
var delegate: UsersUpdatedProtocol?
init(delegate d: UsersUpdatedProtocol) {
super.init()
delegate = d
}
}
// File TableViewController.swift
class TableViewController: UITableViewController, UsersUpdatedProtocol {
var userList: [User] = []
override func viewDidLoad() {
super.viewDidLoad()
let _ = Network(delegate: self)
}
func usersListUpdated(list: [User]) {
self.userList = list
self.tableView.reloadData()
}
}
You could use a notification. Whenever the userlist gets updated, post a notification like this:
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "UserlistUpdate"), object: nil)
Then, in viewDidLoad add:
NotificationCenter.default.addObserver(self, selector: #selector(TableViewController.reloadData), name: NSNotification.Name(rawValue: "UserlistUpdate"), object: nil)
P.S. regarding your architecture so far, I would make the TableViewController hold a variable for Network rather than hold its own user array. Then, in AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let network = Network()
// Access the TableViewController and set its network variable
let tableViewController = window!.rootViewController as! TableViewController
tableViewController.network = network

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