I had a struct merchant in that I had a member post which is dictionary type in that I had name field. So, i want to filter name starting with some text entered in textfield(shouldChangeCharactersIn range textfield delegate). how I can use predicate in this scenario.
For example: I have six name "Pro shop", "table", "Pro merchnat", "Football", "Shop2", "mobile". then i type "pr" then it should give me result "Pro shop", "Pro merchnat".
struct Merchant {
var key: String
var ref: FIRDatabaseReference
var merchant_id: String
var uniquecode: String
var post: NSDictionary
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
ref = snapshot.ref
let snapshotValue = snapshot.value as! [String: AnyObject]
merchant_id = snapshotValue["id"] as? String ?? ""
uniquecode = snapshotValue["uniqueCode"] as? String ?? ""
post = snapshotValue["post"] as! NSDictionary
}
Here is my code what i am trying to do that..
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
for item in merchantArr {
var filteredMerchant = merchantArr.filter{((($0[item] as![String:Any])["post"] as! [String:Any])["name"] as! String).contains(string)}
}
return true
}
Try this
var filteredMerchant = merchantArray.filter{((($0["merchant1414124"] as![String:Any])["post"] as! [String:Any])["name"] as! String).contains("pr")}
Related
I am new to Swift, but have some basic experience with Objective-C programming, and Swift seems much simpler.
However, I can't quite understand the struct thing. I followed a tutorial on how to use Firebase Realtime Database, and this tutorial were using a model to store the data.
But when I modified the struct with additional properties, the previously saved entries in the database is not showing up. I think it's because the model doesn't recognize the object in the database because it has different properties, but how can I make a property optional? So that old entries in the database with different structure (missing properties) are still valid and showing up?
Here is the model. The new property added is all the references to the description.
import Foundation
import Firebase
struct InsuranceItem {
let ref: DatabaseReference?
let key: String
let name: String
let timestamp: Int
let itemValue: Int
let description: String?
let userId: String?
init(name: String, timestamp: Int, itemValue: Int = 0, description: String = "", userId: String, key: String = "") {
self.ref = nil
self.key = key
self.name = name
self.timestamp = Int(Date().timeIntervalSince1970)
self.itemValue = itemValue
self.description = description
self.userId = userId
}
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: AnyObject],
let name = value["name"] as? String,
let timestamp = value["timestamp"] as? Int,
let itemValue = value["itemValue"] as? Int,
let description = value["description"] as? String,
let userId = value["userId"] as? String else { return nil }
self.ref = snapshot.ref
self.key = snapshot.key
self.name = name
self.timestamp = timestamp
self.itemValue = itemValue
self.description = description
self.userId = userId
}
func toAnyObject() -> Any {
return [
"name": name,
"timestamp": timestamp,
"itemValue": itemValue,
"description": description!,
"userId": userId!
]
}
}
The problematic bit is your failable init, init?(snapshot: DataSnapshot). You fail the init even if an Optional property is missing, which is incorrect. You should only include the non-Optional properties in your guard statement, all others should simply be assigned with the optional casted value.
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: Any],
let name = value["name"] as? String,
let timestamp = value["timestamp"] as? Int,
let itemValue = value["itemValue"] as? Int else { return nil }
self.ref = snapshot.ref
self.key = snapshot.key
self.name = name
self.timestamp = timestamp
self.itemValue = itemValue
// Optional properties
let description = value["description"] as? String
let userId = value["userId"] as? String
self.description = description
self.userId = userId
}
Unrelated to your question, but your toAnyObject function is unsafe, since you are force-unwrapping Optional values. Simply keep them as Optionals without any unwrapping and add as Any to silence the warning for implicit coersion.
func toAnyObject() -> Any {
return [
"name": name,
"timestamp": timestamp,
"itemValue": itemValue,
"description": description as Any,
"userId": userId as Any
]
}
This is my data in Firestore:
My comment model:
class CommentModel {
var commentText: String?
var commentDate: NSObject?
var uid: String?
var username : String?
var profileImageUrl: String?
init(dictionary: [String: Any]) {
commentText = dictionary["commentText"] as? String
commentDate = dictionary["commentDate"] as? NSObject
uid = dictionary["uid"] as? String
username = dictionary["username"] as? String
profileImageUrl = dictionary["profileImageUrl"] as? String
}
}
My comments dictionary contains all documents of "comments".
XCode gives me the following suggestion, but I am unsure how to use it.
self.comments.sorted { (CommentModel, CommentModel) -> Bool in
}
How can I sort my dictionary by the commentDate?
You need
self.comments.sort { $0.commentDate < $1.commentDate }
make sure comments is declared as var , also cast it as a Date or String
commentDate = dictionary["commentDate"] as? Date
OR
commentDate = dictionary["commentDate"] as? String
Here is the output of "print(dict)"...
["2018-10-17 11:19:51": {
firstname = Brooke;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Alvarez;
message = hshahyzhshbsbvash;
username = poiii;
}]
["2018-10-17 11:20:31": {
firstname = Trevor;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Bellai;
message = hey;
username = br9n;
}]
["2018-10-17 11:20:44": {
firstname = Amy;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Ikk;
message = hey;
username = nine9;
}]
My code...
Database.database().reference().child("recent-msgs").child(uid!).observe(.childAdded) { (snapshot: DataSnapshot) in
if let dict = snapshot.value as? [String: Any] {
print(dict)
// Store data in user.swift model
let firstnameData = dict[0]["firstname"] as! String
let idData = dict["id"] as! String
let lastnameData = dict["lastname"] as! String
let messageData = dict["message"] as! String
let usernameData = dict["username"] as! String
let rankData = dict["rank"] as! String
let propicrefData = dict["propicref"] as! String
let convoinfo = RecentConvo(firstnameString: firstnameData, idString: idData, lastnameString: lastnameData, messageString: messageData, usernameString: usernameData, rankString: rankData, propicrefString: propicrefData)
self.recentconvos.append(convoinfo)
print(self.recentconvos)
self.tableView.reloadData()
}
}
I'm trying to retrieve the dictionary within the first dictionary which is the value to the key which is the date associate with it. For example: 2018-10-17 11:19:51. However I cannot use this exact string to call it because I must do this without the knowledge of that string.
I tried this:
let firstnameData = dict[0]["firstname"] as! String
But it returns an error:
Cannot subscript a value of type '[String : Any]' with an index of type 'Int'
The error noted above is showing up because you were trying to access the element at a certain position (0) from the dictionary. Dictionaries are not ordered lists, and hence won't have a fixed order of elements to be accessed.
The logged dictionary doesn't really look like a dictionary. Assuming that it is a dictionary, and its keys are the date strings, you can use the following code snippet to parse the dictionary.
class RecentConversation {
var id: String?
var firstName: String?
var lastName: String?
var message: String?
var username: String?
var rank: String?
var propicref: String?
init?(dictionary: [String: Any]?) {
guard let dict = dictionary else {
// Return nil in case the dictionary passed on is nil
return nil
}
id = dict["id"] as? String
firstName = dict["firstname"] as? String
lastName = dict["lastname"] as? String
message = dict["message"] as? String
username = dict["username"] as? String
rank = dict["rank"] as? String
propicref = dict["propicref"] as? String
}
}
Usage:
let dateStrings = dict.keys.sorted {
// Sort in chronological order (based on the date string; if you need to sort based on the proper date,
// convert the date string to Date object and compare the same).
//
// Swap the line to $0 > $1 to sort the items reverse chronologically.
return $0 < $1
}
var conversations: [RecentConversation] = []
for date in dateStrings {
if let conversation = RecentConversation(dictionary: (dict[date] as? [String: Any])) {
conversations.append(conversation)
}
}
You were all very helpful, so I would like to start off by saying thank you. I went ahead and applied the method that lionserdar explained. (.allKeys)
// Fetch Recent Messages
func fetchRecentMsgs() {
// Direct to database child
Database.database().reference().child("recent-msgs").child(uid!).observe(.childAdded) { (snapshot: DataSnapshot) in
if let dict = snapshot.value as? NSDictionary {
print(dict)
print(dict.allKeys)
let keys = dict.allKeys
for key in keys {
print(key)
if let nestedDict = dict[key] as? [String: Any] {
print(nestedDict)
let firstnameData = nestedDict["firstname"] as! String
let idData = nestedDict["id"] as! String
let lastnameData = nestedDict["lastname"] as! String
let messageData = nestedDict["message"] as! String
let usernameData = nestedDict["username"] as! String
Worked for me so I hope this will help others too!
As the title suggests, I'm trying to retrieve some data from firebase database, but my code's not working. I have three children (I guess that's how you call them) inside "Posts" called "title", "description" and "username" and I'm trying to get all of them and append them into a variable to use them later, but it only retrieves the first value of each of them, despite the fact that there are like 5 values. Anyone knows why?
By the way, I'm calling upon this function on my ViewDidLoad.
let postDB = Database.database().reference().child("Posts")
postDB.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
if let snapshotValue = snapshot.value as? NSDictionary {
let postTitle = snapshotValue["title"] as? String
let postUsername = snapshotValue["username"] as? String
let postDesc = snapshotValue["description"] as? String
let postArray = postStruct(title: postTitle, description: postDesc, username: postUsername)
self.newPost.insert(postArray, at: 0)
}
import UIKit
import FirebaseDatabase
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// MARK: - variables
var postDB: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
// getting a node from database //
postDB = Database.database().reference().child("Posts")
// observing data changes //
postDB.observe(DataEventType.value) { (dataSnapshot) in
self.postArray.removeAll()
if dataSnapshot.childrenCount > 0 {
for post in dataSnapshot.children.allObjects as! [DataSnapshot] {
let object = post.value as! [String: Any]
let description = object["description"] as! String
let title = object["title"] as! String
let userName = object["username"] as! String
let model = postStruct(title: title, description: description, username: userName))
self.postArray.append(model)
}
}
self.tableView.reloadData()
}
}
}
Try this – the code replaces what you currently have in the snapshot handler.
if let firebaseList = snapshot.children.allObjects as? [FIRDataSnapshot] {
if let swiftList = snapshot.value as? [String:AnyObject] {
for firebaseItem in firebaseList {
let childID = firebaseItem.key as String
let swiftItem = swiftList[childID]
let postTitle = swiftItem?["title"] as? String
let postUsername = swiftItem?["username"] as? String
let postDesc = swiftItem?["description"] as? String
let postArray = postStruct(title: postTitle, description: postDesc, username: postUsername)
self.newPost.insert(postArray, at: 0)
}
}
}
}
Worked for me. It gets all the values now you just have to put them in an array
postDB.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull #NotNull Task<DataSnapshot> task) {
if(!task.isSuccessful()){
Log.e("firebase", "Error getting data; ", task.getException());
}else{
Log.d("firebase", String.valueOf(task.getResult().getValue()));
}
}
});
This is my NSObject class file that I am using to populate my collectionView cell. I am fetching my data from firebase and populating the collectionViewCell with it. Xcode is giving this error "Missing argument for parameter 'dictionary' in call" I have tried all I can but I could not figure out what is missing. What is causing this error and how can I fix it?
class BusinessCategory: NSObject {
var ref: FIRDatabaseReference!
var name: String?
var logo: String?
var featurebusiness: [SampleBusinesses]?
var type: String?
init(dictionary: [String: Any]) {
self.name = dictionary["BusinessName"] as? String ?? ""
self.logo = dictionary["logo"] as? String ?? ""
}
static func sampleBusinessCategories() -> [BusinessCategory] {
var FinancialInstitutionCatergory = BusinessCategory()
FinancialInstitutionCatergory.name = "Financial Institutions"
var featurebusiness = [SampleBusinesses]()
//logic
FIRDatabase.database().reference().child("BusinessCategories/Banks").observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let financeApp = SampleBusinesses()
financeApp.setValuesForKeys(dictionary)
financeApp.name = dictionary["BusinessName"] as? String
featurebusiness.append(financeApp)
}
FinancialInstitutionCatergory.featurebusiness = featurebusiness
print(snapshot)
}, withCancel: nil)
return [FinancialInstitutionCatergory]
}
}
The error is stating you need to include the dictionary parameter in whatever line has the error; an example might look something like this:
var FinancialInstitutionCatergory = BusinessCategory(dictionary: [String : Any])
It's unclear which line in your code has the error; you'll need to include the parameter somewhere.