Firebase Retrieving and passing data to variable - ios

ridvankucuk Problem
func getHandleStatus() -> String {
var handle = String()
ref.queryOrderedByChild("status").observeEventType(.ChildAdded, withBlock: { snapshot in
if let status = snapshot.value["status"] as? Int {
if status == 0 {
//print(snapshot.key)
handle = snapshot.key
} else {
print("NO")
}
}
})
return handle
}
When i return "handle", its always empty string. I set the variable "handle = snapshot.key" and when i return, its still empty. Please help.

First of all your method is async and it is not waiting the main thread. So writing return makes no sense. You should do something else.
Define a variable outside of the function such as:
var handle: String? = nil {
didSet{
// You know handle is set now
}
}
And update your getHandleStatus method:
func getHandleStatus(){
var handle = String()
ref.queryOrderedByChild("status").observeEventType(.ChildAdded, withBlock: { snapshot in
if let status = snapshot.value["status"] as? Int {
if status == 0 {
//print(snapshot.key)
self.handle = snapshot.key
} else {
print("NO")
}
}
})
}

Related

How to combine two foreach to one in Swift?

I have one function which is having some logic which have 2 foreach loop but i want to make code compact so I am trying to use compactmap
func getData() -> [String] {
var ids = [String]()
self.item?.connections?.forEach { connection in
connection.validLine?.forEach { line in
if let _ = line.connection?.links[LinkKey.dataGroups],
let dataGroups = line.dataGroupsCache, dataGroups.isContinue {
ids += checkinGroups.connections?.compactMap { $0.id } ?? []
}
}
}
return ids
}
so instead of 2 foreach i am trying to make in one by using self.item?.connections?.compactMap({ $0.validline }) but I am getting error saying "Type of expression is ambiguous without more context"
I don't see how you can do it without to forEach or compactMap. Here is a possible solution:
func getData() -> [String] {
return item?.connections?.compactMap { connection in
connection.validLine?.compactMap { line in
guard let _ = line.connection?.links[LinkKey.dataGroups], line.dataGroupsCache?.isContinue == true else { return nil }
return checkinGroups.connections?.compactMap(\.id)
}
}
}
Here's a translation of your post into something that is compilable and a direct translation into a version that doesn't use forEach.
I changed connectionIds to ids in your example because otherwise, you might as well just return [].
class Example {
func getData() -> [String] {
var ids = [String]()
self.item?.connections?.forEach { connection in
connection.validLine?.forEach { line in
if let _ = line.connection?.links[LinkKey.dataGroups],
let dataGroups = line.dataGroupsCache, dataGroups.isContinue {
ids += checkinGroups.connections?.compactMap { $0.id } ?? []
}
}
}
return ids
}
func getDataʹ() -> [String] {
guard let connections = item?.connections else { return [] }
let numberOfProperLines = connections.flatMap { $0.validLine ?? [] }
.filter { line in
if let _ = line.connection?.links[LinkKey.dataGroups],
let dataGroups = line.dataGroupsCache, dataGroups.isContinue {
return true
} else {
return false
}
}
.count
return (0..<numberOfProperLines).flatMap { _ in checkinGroups.connections?.compactMap(\.id) ?? [] }
}
var checkinGroups: CheckInGroups!
var item: Item!
}
enum LinkKey: Int {
case dataGroups
}
struct Item {
let connections: [Connection]?
}
struct Connection {
let id: String?
let validLine: [Line]?
let links: [LinkKey: Void]
}
struct Line {
let dataGroupsCache: DataGroups?
let connection: Connection?
}
struct DataGroups {
let isContinue: Bool
}
struct CheckInGroups {
let connections: [Connection]?
}

How to resolve Escaping closure captures 'inout' parameter 'data'

I have the following function in a separate swift file which I use to make Firebase calls for data:
func fetchPosts(data: inout [Post]) {
postRef.observe(DataEventType.value) { (snapshot) in
data.removeAll() // ***Error thrown here***
if snapshot.value is NSNull {
} else {
var counter: UInt = 0
for item in snapshot.children {
let userID = (item as! DataSnapshot).key
self.postRef.child(userID).observe(DataEventType.value) { (snap) in
counter = counter + 1
for child in snap.children {
if let snapshot = child as? DataSnapshot,
let post = Post(snapshot: snapshot) {
data.append(post) // ***Error thrown here***
}
if (counter == snapshot.childrenCount) {
data = data.sorted(by: { $0.id > $1.id }) // ***Error thrown here***
}
}
}
}
}
}
}
In my view I have the following:
#State var posts: [Post] = [] // which is the place holder for the posts data
and then i have the following call
func fetchPosts() {
postStore.fetchPosts(data: &posts)
}
Which calls the function above and passes the [Post] array by reference
My issue is that I get the following error Escaping closure captures 'inout' parameter 'data' in the above function and I can not figure out what I need to do to resolve it!?
Has anyone ever encountered this error and what do you do to resolve it!?
That won't work with #State, instead you have to use completion callback pattern, like
func fetchPosts() {
self.posts = [] // reset
postStore.fetchPosts() { newPosts in
DispatchQueue.main.async {
self.posts = newPosts
}
}
}
and fetching function
func fetchPosts(completion: #escaping ([Post]) -> () ) {
// ...
var data: [Post] = [] // data is a local variable
// ...
if (counter == snapshot.childrenCount) {
completion(data.sorted(by: { $0.id > $1.id }))
}
// ...
}

DatabaseReference.observe is not called in swift4

I am trying to fetch the data from firebase. I am calling a function which has a databaseReference but it is not calling up.Basically this function is also called from databaseRefernce only of another function.
Here is my code:
func prepareCoursesFromCourseNodewithAllCoursesList(allCourseList: [Any]){
var courseDetailsNode = String()
var courseCount = allCourseList.count
weak var weakSelf = self
var courseId = String()
var localCoursesAndCardDictionary = [AnyHashable: Any]()
for singleCourse in allCourseList as! [[String:Any]] {
if singleCourse["elementId"] != nil {
courseId = "\(String(describing: singleCourse["elementId"]!))"
}else{
if singleCourse["currentCourseId"] != nil {
courseId = "\(String(describing: singleCourse["currentCourseId"]!))"
}
}
if singleCourse["parentNodeName"] != nil {
if singleCourse["parentNodeName"] as! String == "course" {
//this is course
courseDetailsNode = IMERCOURSE_URL
}
else {
//this is course Collection
courseDetailsNode = IMERCOURSECOLLECTION_URL
}
}
var reference = DatabaseReference()
let courseURL = "\(FIREBASE_URL)\(courseDetailsNode.replacingOccurrences(of: "{Id}", with: courseId))"
reference = Database.database().reference(fromURL: courseURL)
self.addIntoListFirebaseRef(firebaseRef: ref)
reference.observe(DataEventType.value, with: { (snapShot:DataSnapshot) in
courseCount -= 1
if snapShot.value != nil {
let singleCourseDictionary = snapShot.value as? [String: Any]
localCoursesAndCardDictionary[courseId] = singleCourseDictionary
self.settingUserDetailsViewData()
(Constants.sharedTools() as AnyObject).hideProgressIndicator()
}
}
}, withCancel: { (error:Error) in
})
}
}
}
this prepareCoursesFromCourseNodewithAllCoursesList(allCourseList: [Any]) is called from another databaseRefernce.ObserveEevnt
value.

Swift Scoping Rules -- nil value after setting a non-nil value

I'm writing a DataService that interfaces with Firebase. I'm setting self.realID within a closure and when I reference it outside the closure, it fails because it unwraps a nil value. Why is this happening?
My file:
import Foundation
import Firebase
class Database {
var firebaseRef = Firebase(url:"https://<<UNIQUE>>.firebaseio.com")
class var sharedInstance: Database {
struct Data {
static var instance: Database?
static var token: dispatch_once_t = 0
}
dispatch_once(&Data.token) {
Data.instance = Database()
}
return Data.instance!
}
var uid : String!
var realID : String!
var validated = false
func validate(user: String, study: String) -> Bool {
firebaseRef.authUser(user+"#example.com", password: user,
withCompletionBlock: { error, authData in
if error != nil {
NSLog(String(error))
} else {
self.uid = authData.uid
NSLog(authData.uid)
}
})
let usersRef = Firebase(url: "https://<<UNIQUE>>.firebaseio.com/users")
usersRef.observeEventType(FEventType.Value, withBlock: { (snapshot) in
let value = snapshot.value.objectForKey("study") as! String
self.realID = value
NSLog(self.realID) // this is a non-nil value
})
NSLog("About to encounter nil value and crash")
if self.realID == study {
return true
}
return false
}
}
How do i prevent this fatal error from happening?
You need to add a completionHandler because it is async request. If you will set the break points then return is executed before you are setting the id.
func validate(user: String, study: String, completionHandler:(Bool) -> Void) {
let usersRef = Firebase(url: "https://<<UNIQUE>>.firebaseio.com/users")
usersRef.observeEventType(FEventType.Value, withBlock: { (snapshot) in
if let value = snapshot.value.objectForKey("study") as? String {
self.realID = value
completionHandler(true)
} else {
completionHandler(false)
}
})
}
UPDATE
validate("Rahul", study: "Study") { (value: Bool) in
if value {
} else {
}
}

bad access code 1 using realm when comparing rlmobject to nil

I have a syncing engine with a server that follows this code for created updated and deleted objects
let lastSynchronizationDate = (NSUserDefaults.standardUserDefaults().objectForKey("com.fridge.sync") as [String: NSDate])["skin"]!
query.whereKey("updatedAt", greaterThanOrEqualTo: lastSynchronizationDate)
query.findObjectsInBackgroundWithBlock { (remoteSkins, error) -> Void in
if error != nil {
return
}
if remoteSkins.isEmpty {
return
}
RLMRealm.defaultRealm().transactionWithBlock {
let deletedSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int == 0
}.map {
Skin(forPrimaryKey: $0["color"])
}.filter {
$0 != nil
}.map {
$0!
}
let createdSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int != 0
}.filter {
let skin = Skin(forPrimaryKey: $0["color"])
println(skin.name)
return skin == nil
}.map { (remoteSkin) -> Skin in
let remoteSkinModel = RemoteSkinModel(remoteSkin)
let skin = Skin()
skin.skinModel = remoteSkinModel // Error
return skin
}
let updatedSkins = (remoteSkins as [PFObject]).filter {
$0["state"] as Int != 0
}.map {
($0, Skin(forPrimaryKey: $0["color"]))
}.filter {
$0.1 != nil
}.map {
$0.1.skinModel = RemoteSkinModel($0.0)
}
RLMRealm.defaultRealm().deleteObjects(deletedSkins)
RLMRealm.defaultRealm().addObjects(createdSkins)
}
}
My skin model:
class Skin: RLMObject {
dynamic var name: String = ""
dynamic var hexString: String = ""
var skinModel: SkinModel! {
didSet {
name = skinModel.name ?? oldValue.name ?? ""
hexString = skinModel.hexString ?? oldValue.name ?? ""
}
}
override class func primaryKey() -> String {
return "hexString"
}
override class func ignoredProperties() -> [AnyObject] {
return ["skinModel"]
}
func save() {
}
}
protocol SkinModel {
var name: String { get }
var hexString: String { get }
}
class RemoteSkinModel: SkinModel {
let remoteSkin: PFObject
let name: String
let hexString: String
init(_ remoteSkin: PFObject) {
self.remoteSkin = remoteSkin
self.name = remoteSkin["name"] as? String ?? ""
self.hexString = remoteSkin["color"] as? String ?? ""
}
}
The first the engine runs everything goes well, but the next time it pops the bad access error when comparing if the realm object is nil or not in the createdSkins' code.
Any idea as to why this would happen?
Thanks in advance
What happens if you force skin to be an optional?
let skin: Sin? = Skin(forPrimaryKey: $0["color"])
if let skin = skin {
println(skin.name)
}
return skin == nil
I think the Swift compiler may be preventing checks to nil because Skin(forPrimaryKey:) should be a failable initializer, but Realm can't mark that as such (only Apple code can have those).
If that's not the issue, let me know and we'll keep troubleshooting this together. (I work at Realm).

Resources