Updating array value using find object in the background is swift - arrays

I'm trying to retrieve data from Parse using findObjectsInbackground and store it in an array. I've already created outside the scoop of viewDidLoad().
I managed retrieving and printing the data, but they are not stored in the array and it keeps being empty!
I used self.articalsTableView.reloadData() but unfortunately the array myArray is still empty.
Any help please, this has been confusing me for two days!
import UIKit
import Parse
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var articalsTableView: UITableView!
var myArray = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Gateshead")
query.findObjectsInBackground {(objects, error) -> Void in
if error != nil {
print(error)
} else {
if let articals = objects {
for artical in articals {
// print (articles) THIS IS WOKING WELL
self.myArray.append(artical)
self.articalsTableView.reloadData()
}
}
}
}
}
}

findObjectsInback is using a background thread and you should dispatch to mainThread whenever if you want to access UIKit stuff in this case updating self.articalsTableView.
Also self.articalsTableView.reloadData() should be called at the end (not in the loop). This to prevent a race condition on self.myArray being accessed by the main-thread (to update self.articalsTableView ) and by the background-thread (to append artical)
for artical in articals {
// print (articles) THIS IS WOKING WELL
self.myArray.append(artical)
}
DispatchQueue.main.async {
self.articalsTableView.reloadData()
}

Related

How can i pass Label from viewController to another one without using segue?

Hi im new in swift and im trying to build a store application, i already build it but i have a problem with only one thing which is , i want to pass the data ( label, image, price label ) to another viewController without using segue. I tried all the method ( delegate, notificationCenter, closure ) but i didn't solve it.
this is a picture for new project i create it to explain what i want to do exactly .
i hope i get the solution because i search alot for it maybe for months but i didn't solve my problem :(
this is my code
passingViewController
import UIKit
extension passingDataViewController : textDelegate {
func sendText(withText: String) {
Label.text = withText
}
}
class receivingDataViewController: UIViewController {
#IBOutlet var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
receivingDataViewController
import UIKit
extension passingDataViewController : textDelegate {
func sendText(withText: String) {
Label.text = withText
}
}
class receivingDataViewController: UIViewController {
#IBOutlet var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
You didn't explain how you're creating the new controllers, but here's a simple example that just uses a tab controller. This makes use of a shared singleton to pass around the delegate, but if you're creating each controller programatically, you could update the delegate when you create each new instance.
For this example, I have created a singleton that contains the delegate
import Foundation
class SharedSingleton : NSObject
{
var updateDelegate : UpdateDelegate?
static let sharedInstance = SharedSingleton()
}
And then we define the protocol you're using.
In the passing view, you can define it like this
protocol UpdateDelegate
{
func updateDisplay(text : String)
}
and you use it (in the passing view like this
var sharedInstance = SharedSingleton.sharedInstance
#IBAction func cmdGo(_ sender: Any) {
sharedInstance.updateDelegate!.updateDisplay(text: txtInput.text!)
}
You define the receiving view to use the update protocol
class ReceivingViewController: UIViewController, UpdateDelegate {
and set up the delegate
var sharedInstance = SharedSingleton.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// setup the delegate through the shared instance
sharedInstance.updateDelegate = self
}
and then implement the update method
func updateDisplay(text: String) {
lblDisplay.text = text
}
That's it. You may need to update your implementation to change how you share the delegate pointer, but that's the process.

How to pass data into swiftui view and access it

Im trying to pass data into a swiftui view to be displayed when it is initialized, but am having trouble getting it to work.
Here is my code which passes data into my 'MarkerInfoWindow.swift' view:
func mapView(_ mapView: GMSMapView, markerInfoContents marker: GMSMarker) -> UIView? {
print("Showing marker infowindow")
print("marker.userData: \(marker.userData)")
let mUserData = marker.userData as? [String:String]
print("mUserData?['name']", (mUserData?["name"]) ?? "mUserData[name] was nil")
let mInfoWindow = UIHostingController(rootView: MarkerInfoWindow(placedata: mUserData!))
return mInfoWindow.view
}
Here is the code to my 'MarkerInfoWindow.swift' view:
struct PlaceDataStruct {
var name : String
var place_id : String
}
struct MarkerInfoWindow: View {
var placedata: [PlaceDataStruct]
var body: some View {
//Here is where i keep getting errors regardless if i use this method or dot notation
Text(placedata["name"])
}
}
Im not sure if im implementing my PlaceDataStruct incorrectly.
Does anyone know what I'm doing wrong, so that I can display the right data every time my view is initialized?
You’re MarkerInfoWindow is expecting an array of structs but the data you are passing is a dictionary, in the form [String: String]
You should update your MarkerInfoWindow to accept a dictionary instead. Here is an example of how to do that.
struct MarkerInfoWindow: View {
var placedata: [String: String] // update to be dictionary
var body: some View {
Text(placedata["name", default: ""]) // use correct notation for accessing dictionary
}
}
You’re also force unwrapping the data before you pass it to your MarkerInfoWindow if that’s your intention that is ok. But note that if your data isn’t there then it will crash your app.

Accessing final array after fetching from Firebase in Swift

I'm trying to fetch relational data from firebase in swift 3 and storing it in an array. It does fetch everything the way I want it to but i can't access the final array to work with.
I have tried everything I found online but can't make it work properly.
There are 3 child nodes I'm fetching, so every time it fetches it appends it to the array.
The output is:
success
success
success
I just want it to print "success" once.
Here is my code:
// Here the child with the relations is loaded
func fetchFollowingSection1IDs() {
guard let userID = FIRAuth.auth()?.currentUser?.uid else { return }
let reference = FIRDatabase.database().reference().child("interests").child("relations").child("userAndSection1").child(userID)
reference.observe(.childAdded, with: { (snapshot) in
// It's supposed to fetch the details of Section1 according to the childs from the relations (they are the IDs of Section1)
self.fetchSection1(section1ID: snapshot.key, completionHandler: { success in
guard success == true else {
return
}
print("success")
self.collectionView?.reloadData()
})
}, withCancel: nil)
}
// Here it gets the details from Firebase
func fetchSection1(section1ID: String, completionHandler: #escaping (Bool) -> ()) {
let ref = FIRDatabase.database().reference().child("interests").child("details").child("country").child("section1").child(section1ID)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
self.collectionView?.refreshControl?.endRefreshing()
if let dictionary = snapshot.value as? [String: AnyObject] {
let section1 = Section1New(section1ID: section1ID, dictionary: dictionary)
self.section1s.append(section1)
}
completionHandler(true)
}) { (err) in
print("Failed to fetch section1s:", err)
}
}
My Firebase structure for the relations looks like this:
"interests" : {
"relations" : {
"userAndSection1" : {
"7fQvYMAO4yeVbb5gq1kEPTdR3XI3" : { // this is the user ID
"-KjS8r7Pbf6V2f0D1V9r" : true, // these are the IDs for Section1
"-KjS8tQdJbnZ7cXsNPm3" : true,
"-KjS8unhAoqOcfJB2IXh" : true
},
}
Everything loads properly and populates my collection views. It is just the problem that it is the wrong number of Section1s because of the triple appending to the array.
Thank you for your answers!
The code is doing exactly what you are telling it to do.
Your firebase event is .childAdded so it will iterate over each child node one at a time.
It first loads -KjS8r7Pbf6V2f0D1V9r and adds it to the section1s array - there is then one item in the array.
Then it loads -KjS8tQdJbnZ7cXsNPm3 and appends to the array. There's two items in the array and two lines output. etc.
The only thing we don't see in the code in your question is the line that actually prints the array, which is probably in your collectionView delegate methods.
Depending on your use case, you may want to read everything in with .value, and then iterate over that to populate your dataSource array.

Swift error Trying to Pass Array to Another Class

So I am probably doing this all wrong but I want to make a shopping list app and I have two view controllers, one with the list and one with a textbook and button to add to the list but I can't figure out how to get the array to the other class. I have this code so far and the error I get is
Instance member 'list' cannot be used in type 'mainViewController'
And this is my code
import UIKit
class mainViewController: UIViewController {
var list:[String] = [""]
#IBOutlet weak var item: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
// Do any additional setup after loading the view.
}
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(mainViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
#IBAction func AddToList(sender: UIButton) {
list.append(item.text!)
}
static func getList(inout Array: [String]) -> [String] {
return list
}
}
Any help much appreciated, please keep it positive though and keep in mind I am very new to this forum and swift. Thanks!
The error message is very clear that you are trying to access an instance field in type context (without instance).
To fix it, just remove static in getList function.
PS: Please follow Swift naming conventions to capitalize your class name

(Swift) How to create global array?

I am trying to create a global array (of items in a cart) in Swift so that I can access it from different pages.
Can you please point me in the right direction? declaring an array under the import statement in AppDelegate gives me the "unresolved Identifier" issue.
What should I use? How can I accomplish that? Thank you!
In swift you can encapsulate variables in a struct and you can access them anywhere.
struct GlobalVariables {
static var globalString = "MyString"
}
To call it
// Get value
let str = GlobalVariables.globalString
// Set value
GlobalVariables.globalString = "New value"
Checkout the reference for more information.
first controller: declare variable
import UIKit
class ViewController: UIViewController {
var test2 = 5
override func viewDidLoad() {
super.viewDidLoad()
}
}
second controller call variable
class ViewController1: UIViewController {
var myCustomViewController: ViewController = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
print(myCustomViewController.test2)
} }

Resources