How to get data from firebase to another view controller - swift

I have a picker view to select an office and I have informations about them.
I added all informations about offices to firebase
of
firmname
firm: "AAAA"
officename
office: "BBBB"
phone
phone: "23424234"
user
user: "a#a.com
let firmname = ["firm" : "AAAA"]
let officename = ["office" : "BBBB"]
let username = ["user" : "a#a.com"]
let phone = ["phone" : "23424234"]
let cref = root.child("of")
let of = ["firmname": firmname, "officename": officename, "user": username,"phone": phone]
cref.setValue(of)
I want to get for example just officename from another view controller.

Well you have a lot of strategies, a simple one would be to:
create an Office object in your second View Controller
let myOffice = Office()
in the first view Controller, implement the prepareForSegueWithIdentifiermethod:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "YourSegueIdentifierHere") {
if let viewController = segue.destinationViewController as? YourSecondViewController {
viewController.myOffice = of
}
}
}

Related

core data and relationship predicate

I've start swift & core data few month ago usually I've found my answer on this website but for the first time I'm really stuck with "Relationship" and "Predicates"
I've created a first view controller with a tableview which is populated by the user and this part is working like I wish.
The user can "tap" a cell and open a new view controller with a new tableview and I'd like populate this tableview with data that in relation with the cell the user tapped.
I'm using CoreData and I've set 2 entities : "Compte" and "Operation" they are in relationship by ONE TO MANY (ONE compte for MANY operation)
Here where I am :
when the user tap the cell i'm using segue to send the "Compte" to the second view controller :
//Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let guest = segue.destination as! OperationsViewController
let indexPath = tableView.indexPathForSelectedRow
let operation = fetchedResultController.object(at: indexPath!)
guest.compteTestRelation = operation
}
In the OperationsViewController i've set this variable :
var compteTestRelation: Compte!
for testing my data I've create a FOR LOOP like this and a FUNCTION:
for index in 1 ... 10 {
let newOp = Operation(context: context)
newOp.nom = "Test Compte \(index)"
newOp.date = NSDate()
newOp.moyenPaiement = "Test"
compteTestRelation.addToRelationCompte(newOp) // RelationShip
}
do {
try context.save()
} catch {
print(error.localizedDescription)
}
the FUNCTION
func displayOperation() {
if let opList = compteTestRelation.relationCompte as? Set<Operation> {
sortedOperationArray = opList.sorted(by: { (operationA:Operation, operationB:Operation) -> Bool in
return operationA.date!.compare(operationB.date! as Date) == ComparisonResult.orderedAscending
})
print(sortedOperationArray)
}
}
In the console with "print" It work like I wish depend the cell is tapped the print(sortedOperationArray) appear or not
My problem now is how populate my tableview with this data, when I use predicates in my FetchResultController I've got error or an empty tableview but in the console everything seems to work so I'm thinking the relationship is OK ..
If I don't use PREDICATE I can populate my tableview with the data but I see always ALL the data
I've seen other similar problems and answers on stackoverflow.com but nothing work for the moment.
Thank You! :)
I've found an another way to predicate my data and it works for me now
I've create a new attribute in my OPERATION entity called "id" and when I create my data I attribute an ID like this :
for index in 1 ... 10 {
let newOp = Operation(context: context)
newOp.nom = "Test Compte \(index)"
newOp.date = NSDate()
newOp.moyenPaiement = "Test"
newOp.id = "id123\(compteTestRelation.nom!)"
compteTestRelation.addToRelationCompte(newOp) // RelationShip
}
do {
try context.save()
} catch {
print(error.localizedDescription)
}
then I predicate my data like this in my FetchResultController :
func setupFetchedResultController () {
let operationsRequest: NSFetchRequest<Operation> = Operation.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "nom", ascending: true)
let keyPath = "id"
let searchString = "id123\(compteTestRelation.nom!)"
let operationsPredicate = NSPredicate(format: "%K CONTAINS %#", keyPath, searchString)
operationsRequest.returnsObjectsAsFaults = false
operationsRequest.sortDescriptors = [sortDescriptor]
operationsRequest.predicate = operationsPredicate
fetchedResultController = NSFetchedResultsController(fetchRequest: operationsRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
do {
try fetchedResultController.performFetch()
} catch {
print(error.localizedDescription)
}
}

Segue async Firebase data through NavigationController (Swift)

I have been chasing this for two days but yet I am still not sure why my variable isn't being passed in my segue from my login view controller to the chat view controller via the navigation view controller.
I have a button that queries Firebase, checks if the user exists and returns a Firebase query reference for the user. I then want to pass this Firebase query reference when it finishes to the navigation controller's top view controller for use.
Inside my IBAction login button, I have:
var tempUserRef: FIRDatabaseReference?
channelRef.queryOrdered(byChild: "uid").queryEqual(toValue: uid).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
print("uid exist with \(snapshot.childrenCount) number of children")
for s in snapshot.children.allObjects as! [FIRDataSnapshot] {
tempUserRef = self.channelRef.child(s.key)
}
} else {
print("uid didn't exist")
if let name = self.nameField?.text { // 1
tempUserRef = self.channelRef.childByAutoId()
let channelItem = [
"name": name,
"uid": self.uid
]
tempUserRef?.setValue(channelItem)
}
}
self.userRef = tempUserRef
DispatchQueue.main.async {
self.performSegue(withIdentifier: "LoginToChat", sender: tempUserRef)
print("passsed \(self.userRef)")
}
})
Here is my segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if "LoginToChat" == segue.identifier {
if let navVc = segue.destination as? UINavigationController {
if let chatVc = navVc.topViewController as? ChatViewController {
chatVc.senderDisplayName = nameField?.text
if let userRef = sender as? FIRDatabaseReference {
chatVc.userRef = userRef
print("passsing \(self.userRef) to \(chatVc)")
}
}
}
}
super.prepare(for: segue, sender: sender)
}
The print statements all look good on my login controller but when I get to the chat view controller, the userRef is still nil. So my sense is that I have the right segue inputs and handoffs but that the async nature of the data is somehow out of step with my segue.
The chat view controller is using the JSQMessages library if that makes a difference.
Thanks for your help.
EDIT:
Based off feedback I've moved the super.prepare but userRef is still not being set consistently.
SECOND EDIT:
Following paulvs' suggestion, I removed my button segue. However, I did have to create another segue that connected view controller to view controller like this SO question.
Place the call to super.prepare at the end of the function. Otherwise, the segue is performed before you set your variables.

TableView segue with multipe arrays

I have a table view with two sections, both calling two different arrays.
var data1 = [Data]()
var data2 = [Data]()
let section = ["Section1", "Section2"]
How can I pass the information of both through a segue?
This is my information for the segue, "Data" is a struct on a seperate file.
let destination = segue.destinationViewController as! DetailsViewController
let selectedInfo = data1[indexPath.row]
destination.detailsTitle.text = selectedInfo.dataTitle
destination.detailsImage.image = selectedInfo.dataImage
destination.detailsInfo.text = selectedInfo.dataDetails
destination.detailsGenre.text = selectedInfo.dataGenre
But I have two arrays, and I'm not sure how to go about it. Also, this information doesn't work. It says the passed information is nil and my app crashes. Both arrays have information append to it.
This is the whole segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == cellIdentifier {
let destination = segue.destinationViewController as! DetailsViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedInfo = data1[indexPath.row]
destination.detailsTitle.text = selectedInfo.dataTitle
destination.detailsImage.image = selectedInfo.dataImage
destination.detailsInfo.text = selectedInfo.dataDetails
destination.detailsGenre.text = selectedInfo.dataGenre
}
}
}
The information on my arrays is this...
let pic1 = UIImage(named: "killlakill")
var animeInfo = Data(title: "Kill la Kill", image: pic1!, details: "The story is set on a high school that the student council president Satsuki Kiryuuin rules by force. Wielding a giant Basami scissors sword, the wandering transfer student Ryuuko Matoi brings about upheaval on the campus. Ryuuko searches for the mysterious figure who caused her father's death, but confronting her are the student council's four divine kings. Fortunately, Ryuuko is aided by a talking sailor uniform who tells her, Wear me. When I am worn by you, this power will become manifest.", genre: "School, Comedy, Action", episodes: "24")
data1.append(animeInfo)
And so on...
In the table view controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let row = self.tableView.indexPathForSelectedRow?.row {
if let section = self.tableView.indexPathForSelectedRow?.section {
let destination = segue.destinationViewController as! DetailsViewController
if section == 0 {
let selectedInfo = data1[row]
destination.data = selectedInfo
}
else if section == 1 {
let selectedInfo = data2[row]
destination.data = selectedInfo
}
}
}
}
In the second view controller, have:
var data = Data()
Then use the information from data to fill in your labels and such:
override func viewDidLoad() {
super.viewDidLoad()
detailsTitle.text = data.dataTitle
detailsImage.image = data.dataImage
detailsInfo.text = data.dataDetails
detailsGenre.text = data.dataGenre
}
Change your data property to:
let data = [Data, Data]
And then in your segue use:
let selectedInfo = data[indexPath.section][indexPath.row]

Swift, segue information passed won't show

I'm trying to get some information to pass to another view controller. I did the segue and nothing is showing. I'm using an external class to organize the information. But I'm not sure why it's not working.
first view controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toLocationVC" {
let lVC = segue.destinationViewController as! LocationViewController
lVC.locationImage?.image = locations[locationSelection].image;
lVC.nameLabel?.text = locations[locationSelection].name;
lVC.descriptionTextView?.text = locations[locationSelection].desc;
}
second view:
var selectedLocation : Location?;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationImage.image = selectedLocation!.image
nameLabel.text = selectedLocation!.name
descriptionTextView.text = selectedLocation!.desc
}
and this is the class Location:
class Location {
var image : UIImage
var name : String
private var description : String
var desc : String {
return description + "\n\n\nThis Description and Images Provided by http://www.travel.usnews.com"
}
init(name : String, image : UIImage, description: String) {
self.name = name;
self.image = image;
self.description = description;
}
}
I've tried changing some of the code around, but nothing seems to work.
Obviously you override the information you just set prepareForSegue() in your second view controller's viewDidLoad() method.
Just remove the following code from your viewDidLoad() and it should be working (if this is actually the correct segue and all data are set):
locationImage.image = selectedLocation!.image
nameLabel.text = selectedLocation!.name
descriptionTextView.text = selectedLocation!.desc
(And I got the feeling that the selectedLocation is nil (= not set) in the viewDidLoad().)
I would rewrite the segue as follows:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toLocationVC" {
if let lVC = segue.destinationViewController as? LocationViewController {
lVC.selectedLocation = locations[locationSelection]
}
}
Then set a breakpoint inside the if let lVC = segue...{ block to see if it's ever executed. Step through the code and use the po {variable name here} command in the debugger to look into each variable.
You shouldn't be setting anything in the viewDidLoad() function any longer like Mischa suggested. So delete those assignments.
If this answer doesn't help, I think you'll need to update your code listings to include more information. We can't see exactly where a lot of these variables are declared, or if the second view is the correct class.

Remove/Hide UITabBarItem in Swift

I have looked really hard for this solution in Swift but am not coming up with one that works for me. I am trying to hide my "Admin" TabBarItem based on the permissions of the person that logs in to the app. I can disable it but it still shows up on the bar. I want to be able to show it for certain people and hide it for others. Also, when I print self.tabBarController?.viewControllers I get nil.
class TabBarMenuController: UITabBarController {
let ref = Firebase(url: "")
var position = ""
func getPosition() {
let userRef = ref.childByAppendingPath("users/\(ref.authData.uid)")
userRef.observeSingleEventOfType(.Value, withBlock: {snapshot in
if snapshot.value["position"] as! String != "Staff" {
self.position = snapshot.value["position"] as! String
}
})
}
override func viewWillAppear(animated: Bool) {
getPosition()
print(self.tabBarController?.viewControllers)
if position != "Staff" {
if let tabBarController = self.tabBarController {
let indexToRemove = 3
if indexToRemove < tabBarController.viewControllers?.count {
var viewControllers = tabBarController.viewControllers
viewControllers?.removeAtIndex(indexToRemove)
tabBarController.setViewControllers(viewControllers, animated: true)
}
}
}
}
Also, I keep reading that this is against Apple's intended use. Is that true still? Is there a better workflow to accomplish that type of functionality?
I would create a tab that opens up the user's account and have a button in the user VC tab that opens up a page for admins only. you can show and hide the button as needed using adminButton.hidden = true or adminButton.hidden = false.