Passing data between view controllers inside UITabBarController without segues - ios

I have been looking for answer to this question for a long time. I can use prepareforSegue if I am using segues. As we know, UITabBar doesn't have segues like navigation controller. In one of my view controllers, I am fetching data from firebase, and I have observer set up to listen for any changes. I want to use data fetched from firebase in this controller to access in another view controller. For example, I want to access this entryIDs in another view controller, and also listen to any changes made to this array, so I can reload data in my collectionView. To sum it up, how do I access array from one view controller to another inside UITabBarController, and also listen to any changes made to it?
var entries = [String: DiaryEntry]()
var entryIDs = [String]()
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
self.collectionView!.register(DiaryCell.self, forCellWithReuseIdentifier: "homeCell")
collectionView?.backgroundColor = UIColor.white
if let userID = FIRAuth.auth()?.currentUser?.uid {
FirebaseService.service.getUserEntriesRef(uid: userID).observe(.value, with: { [weak weakSelf = self] (snapshot) in
weakSelf?.entries = [String: DiaryEntry]()
weakSelf?.entryIDs = [String]()
let enumerator = snapshot.children
while let entry = enumerator.nextObject() as? FIRDataSnapshot {
weakSelf?.entryIDs.append(entry.key)
weakSelf?.entries[entry.key] = DiaryEntry(snapshot: entry)
}
weakSelf?.entryIDs.reverse()
weakSelf?.collectionView?.reloadData()
})
}
// Do any additional setup after loading the view.
}

On sending info
let infoDict = ["info" : self.info]
NotificationCenter.default.post(name: Notification.Name(rawValue: "passInfo"), object: nil, userInfo : infoDict as! [String : AnyObject])
on receiving info
NotificationCenter.default.addObserver(self, selector: #selector(self.doSomething), name: NSNotification.Name(rawValue: "passInfo"), object: nil)
func doSomething(_ notification : Notification) {
let info = notification.userInfo!["info"] as! Int
//Do something
}

Related

How to send data from RightViewController to MainView Controller in Swift 4?

Hello, I am using MMDrawerController for right side menu. I have 2 ViewController First is HomeVC with Product Listing data in UICollectionView and there's 1 filter button.
When i press that filter button I push to filter screen RightViewVC. Now what I want is, I want to pass that selected filter values to HomeVC. How can I do this?
You can do this by multiple way
1. By using Block Method
When you push to RightViewVC write below code.
let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "RightViewVC") as! RightViewVC
nextViewController.delegate = self as! customeDelegate
nextViewController.onApplyFilterTap = {(_ arrSelectedFilter: NSMutableArray) -> Void in
self.collectionView.reloadData()
}
self.show(nextViewController, sender: self)
Define this in RightViewVC controller. I created array you can change it as per your requirement.
var onApplyFilterTap: ((_ arrSelectedFilter: NSMutableArray) -> Void)? = nil
You need to call like this
self.arrFilterSelection.add(whichButtonClicked)
self.arrFilterSelection.add(locationTextView.text!)
self.arrFilterSelection.add(byPriceToTextField.text!)
self.arrFilterSelection.add(byPriceFromTextField.text!)
self.arrFilterSelection.add(timeTextview.text!)
onApplyFilterTap!(self.arrFilterSelection)
2. By using NotificationCenter
Write below in your HomeVC
NotificationCenter.default.addObserver(self, selector: #selector(refreshProductListBasedonSelectedFilterValue(_:)), name: NSNotification.Name(rawValue: "refreshProductListBasedonSelectedFilterValue"), object: nil)
#objc func refreshProductListBasedonSelectedFilterValue(_ notification: Notification) {
let info = notification.object as? NSDictionary
let arrSelectedFilteredValues = info?.value(forKey: "selectedFilter") as! NSMutableArray
self.collectionView.reloadData()
}
From RightViewVC you need to call like this.
let dict = NSMutableDictionary()
dict.setValue(self.arrFilterSelection, forKey: "selectedFilter")
NotificationCenter.default.post(name: NSNotification.Name("refreshProductListBasedonSelectedFilterValue"), object: dict)
3. You can also use delegate

How to insert data to TableView in another view controller Swift 4?

I have ViewControllerA and ViewControllerB. I make a network call in ViewControllerB,when it success,I want to insert a data to the TableView in ViewControllerA,so the data can appear as 1st item in the TableView.
Here is what I tried:
ViewControllerB
var myItem = [Item]() //here is the array in ViewControllerA
Alamofire.request(MyURL!, method: .post, parameters: params, encoding: URLEncoding.httpBody, headers: headers).responseJSON{
response in
switch response.result{
case .success(let result):
let json = JSON(result)
if let myJson = json.dictionary,let myItem = Item.init(dict: myJson){
self.myItem.insert(newPost, at: 0)
NotificationCenter.default.post(name: .reload, object: nil) //here I call notification center after insert to the array
self.dismiss(animated: true, completion: nil)
self.tabBarController?.selectedIndex = 0 //back to ViewControllerA
}
case .failure(let error):
print("error = \(error)")
}
}
In ViewControllerA (which contain the tableView)
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(updateTableView), name: .reload, object: nil)
}
#objc func updateTableView(_ notification: Notification){
print("here get called")
self.tableView.reloadData()
}
I create an extension for the NotificationCenter
extension Notification.Name {
static let reload = Notification.Name("reloadTableView")
}
After done all this,the item that I insert to the array of ViewControllerB didnt appear in the 1st place of TableView in ViewControllerB.
I make a print in updateTableView() function which will call when received response from NotificationCenter in ViewControllerA,it get called,but the data is not appear.
I cant use segue,cause the both ViewController are 2 of the tab in TabbarController.
So in this case,how can I insert the data from ViewControllerB to TableView of ViewControllerA?
The problem is that you create a new array by this line
var myItem = [Item]()
But the viewControllerA use the different array. Try to send a new array in notification
NotificationCenter.default.post(name: .reload, object: self.myItem)
Then in viewControllerA set the new array.
#objc func updateTableView(_ notification: Notification){
var newItems = notification.object as! [Item]
arrayOfControllerA.append(contentsOf: newItems)
self.tableView.reloadData()
}

Cannot retrieve recently added values with Firebase

I have two view controllers in my app: the first one displays items pulled from a Firebase database, and the second one lets users add and remove items from the database.
The problem is when a user adds an item in the second view controller and goes back to the first controller really fast. This will sometimes cause the Firebase database not save the item. As a consequence the first view controller won't to display the newly added items.
As far as the implantation goes, I fetch items in viewWillAppear and then remove the Firebase listener observer in viewDidDisappear. How can I fix this?
// first view controller code
var items = [Item]()
var ref: FIRDatabaseReference!
func fetchItems() {
ref.child("items").observeSingleEvent(of: .value, with: { (snapshot) in
self.items = []
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
if let dictionary = child.value as? [String: AnyObject] {
// Create item and append it to an items array
}
}
self.tableView.reloadData()
})
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.fetchItems()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
ref.removeAllObservers()
}
You shouldn't use observeSingleEvent since you want the code to be executed every time the firebase database changes. So, change it:
func fetchItems() {
ref.child("items").observe(.value, with: { (snapshot) in
self.items = []
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
if let dictionary = child.value as? [String: AnyObject] {
// Create item and append it to an items array
}
}
self.tableView.reloadData()
})
}
This will create a listener. Also, since you didn't create an observer before, you didn't have to use removeAllObservers(). Now that you have one it's correct to use it.
Hope it helps!

Swift iOS -Which viewController lifecycle event to use to send data to Firebase after a view changes

I have some information to send to Firebase. The thing is I want to send the data but I also have to pull the data from there first. The data I get is based on the users input.
I'm already making several nested async calls to Firebase. Not only do i have to wait for the calls to finish to make sure the data has been set but I don't want to have the user waiting around unnecessarily when they can leave the scene and the data can be pulled and changed in a background task.
I was thinking about using a NSNotification after the performSegueWithIdentifier is triggered. The observer for the notification would be inside viewWillDisappear.
Is this safe to do and if not what's the best way to go about it?
Code:
var ref: FIRDatabaseReference!
let uid = FIRAuth.auth()?.currentUser?.uid
let activityIndicator = UIActivityIndicatorView()
override func viewDidLoad() {
super.viewDidLoad()
self.ref = FIRDatabase.database().reference().child(self.uid!)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(fetchSomeValueFromFBThenUpdateAndResendAnotherValue), name: "FbFetchAndSend", object: nil)
}
#IBAction func buttonPressed(sender: UIButton) {
activityIndicator.startAnimating()
levelTwoRef //send levelTwo data to FB run 1st callback
scoreRef //send score data to FB run 2nd callback
powerRef //send power data to FB run 3rd callback
lifeRef //send life data to FB run Last callback for dispatch_async...
dispatch_async(dispatch_get_main_queue()){
activityIndicator.stopAnimating()
performSegueWithIdentifier....
//Notifier fires after performSegue???
NSNotificationCenter.defaultCenter().postNotificationName("FbFetchAndSend", object: nil)
}
}
func fetchSomeValueFromFBThenUpdateAndResendAnotherValue(){
let paymentRef = ref.child("paymentNode")
paymentRef?.observeSingleEventOfType(.Value, withBlock: {
(snapshot) in
if snapshot.exists(){
if let dict = snapshot.value as? [String:AnyObject]{
let paymentAmount = dict["paymentAmount"] as? String
let updatePayment = [String:AnyObject]()
updatePayment.updateValue(paymentAmount, forKey: "paymentMade")
let updateRef = self.ref.child("updatedNode")
updateRef?.updateChildValues(updatePayments)
}
You are adding the observer in viewWillDisappear, So it won't get fired because it won't be present when your segue is performed.
Add the observer in viewDidLoad and it will work.
But if you just want to call fetchSomeValueFromFBThenUpdateAndResendAnotherValue() when the view is disappearing then there is no need for observer.
Simply call the method on viewWillDisappear like this -
override func viewWillDisappear(animated: Bool)
{
super.viewWillDisappear(animated)
fetchSomeValueFromFBThenUpdateAndResendAnotherValue()
}

Passing data between two view controllers are not working

I am trying to pass some data between two view controllers, but it doesn't work..
This is the data i am trying to pass(these has items from parse.com - the same code is in both view controllers):
var userFile = [PFFile]()
var createdAt = [NSDate]()
var objID = [String]()
This is the button for open the view controller(inside the first view controller i am trying to send data FROM):
#IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
}
The view controller is a ModalViewController.xib connected to ViewStoryModalViewController.swift
This is the viewDidLoad in the view controller i am trying to send data TO:
override func viewDidLoad() {
super.viewDidLoad()
print("USERFILECOUNT: \(self.userFile.count)")
}
My problem is that this is the messages i get in xCode output:
What might be wrong here? Any suggestions?
xCode output tells that an array self.userFile contains zero elements, It doesn't mean that it is passed wrong. It is just empty.
print("USERFILECOUNT: \(self.userFile.count)")
Check if it is empty before passing it to modal vc.
Try this code
You first need to present after that try to set variable.
IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
}

Resources