-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Database.database()
is nil
despite being nonnull
#2419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This comment has been minimized.
This comment has been minimized.
Hey @pepasflo, sorry for the troubles you're seeing. A few questions:
The only situation If you could please help provide that information and ideally a sample project we can get it fixed right away, and with the versioning information I can hopefully point you to a version in the meantime that's working as expected. Sorry again for the troubles and thanks for reporting this, we really appreciate it! Update: I changed the title to be more specific to the exact issue, hope that's okay. |
Database.database()
is nil
despite being nonnull
@ryanwilson we used to have an assertion there that would fail on access if the database instance wasn't nil. Did we remove that? Edit: Looks like all the assertions are still there. |
@morganchen12 I'm fairly certain we did not - we do check two things though, if the default app is configured here:
and in this method (called through the
|
I've seen this kind of thing happen before if there's duplicate class implementations in the runtime. @pepasflo can you share a sample that reproduces this issue? |
Hi @ryanwilson Thank you for being gracious and tolerant in the face of my crankiness. A bit of background -- we've had Firebase working in our iOS app, and I needed to spin up a little demo app to try something out. I created a new Xcode project, installed Firebase DB via cocoapods, dragged in a copy of our plist file from google, renamed the bundle ID of the demo app to match our production app, and pasted this into func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let path = Bundle.main.path(forResource: "firebase-staging-livecoverage", ofType: "plist")!
let options = FirebaseOptions(contentsOfFile: path)!
FirebaseApp.configure(options: options)
let db = Database.database()
if db == nil { fatalError("❌ db is nil") }
let ref = db.reference(withPath: "live/9747")
if ref == nil { fatalError("❌ ref is nil") }
ref.observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
print("✅ firebase snapshot: \(snapshot)")
}, withCancel: { (error) in
print("❌ firebase error: \(error)")
})
window?.rootViewController = UIViewController()
return true
} which fails with Pasting the same code into our production app works as expected, returning the JSON corresponding to My hunch is that this is 99% likely to be some sort of configuration step which I've missed or other mistake I've made while setting up the demo project. But, rather than solving my particular problem, hopefully we can figure out the circumstances under which the db is Happy to follow-up with more details! |
No problem at all, this is an ugly bug and hopefully we can track down what's causing this. Are you able to paste the contents In the meantime I'll take a look to see if I can reproduce this. |
Hmm, looks like I ended up with different versions of Firebase between the production app and the demo. Working production app:
Demo with nil db:
|
Hmm, I'll try recreating that demo and see if I can get it to use the latest Firebase from cocoapods. |
This is super helpful, please do try the latest version and let us know if you get the same issue. I'll be away from the keyboard for a bit but back within the next hour to check in. |
Oh, I think I see the versioning issue: I called for
which results in
|
Aha.
|
Hmm, same failure in the demo with the latest firebase: I'll see if I can create a new google plist from scratch for the demo. |
Nope. Registered a new app with Firebase, new plist, changed the app ID to match (tv.flosports.ott.staging-livecoverage-demo2), db is still nil. There must be some setup step I'm overlooking. |
Instead of renaming the plist, I went with the default name (GoogleService-Info.plist) and changed the configure line to |
Ok, it turns out this was due to not including This:
results in the This does not:
Update: to be clear, this was the solution to the problem (adding |
Very interesting, thanks so much for tracking this down.
|
Yep, |
Hmm, it looks like Core was already listed as a pod dependency on Database, not sure why this is happening.
|
I created an example project, pasted the exact I get a I tried using A few other thoughts:
Thanks again for trying to help us solve this, I want to make sure we can get you back up and running as well as verify all our documentation is correct. |
Ok, full reproduction details: Recreate the failing case
this will result in the following
Replace import UIKit
import FirebaseCore
import FirebaseDatabase
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let db = Database.database()
if db == nil { fatalError("❌ db is nil") }
let ref = db.reference(withPath: "live/9747")
if ref == nil { fatalError("❌ ref is nil") }
ref.observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
print("✅ firebase snapshot: \(snapshot)")
}, withCancel: { (error) in
print("❌ firebase error: \(error)")
})
window?.rootViewController = UIViewController()
return true
}
} (replace
Recreate the working case
(Notice that it installed a different set of dependencies) This will result in the following
Replace import UIKit
import FirebaseCore
import FirebaseDatabase
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let db = Database.database()
if db == nil { fatalError("❌ db is nil") }
let ref = db.reference(withPath: "live/9747")
if ref == nil { fatalError("❌ ref is nil") }
ref.observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
print("✅ firebase snapshot: \(snapshot)")
}, withCancel: { (error) in
print("❌ firebase error: \(error)")
})
window?.rootViewController = UIViewController()
return true
}
} (replace
Podfile.lock differencesThe only difference between these two projects seems to be the dependencies which get installed:
My guessSince most of this is written in Obj-C, my first guess is that if a certain dependency isn't installed, this ends up translating into an object being Of course, I haven't delved into the code, so take that with a grain of salt :) |
To summarize, my understanding is that this (missing) single line in the
(what led to discovering this was going back to the "getting started" docs, noticing that they included |
Here's the difference in resulting installed dependencies in a bit easier to read form:
|
@pepasflo I appreciate the full set of details! Attempting to match your setup, with any differences that matter in bold:
Only the project name is different.
Same as your output.
Difference: CocoaPods version. Replaced the Did not fail with
The biggest difference appears to be CocoaPods Does anything get logged to the console for you in the failure case? |
@ryanwilson oh interesting, I've never had anything trigger that error block yet. This is what I see in the console:
Note: what started me down this rabbit hole was trying to get Firebase working on tvOS. I had created a similar trivial demo app, noticed that it did work, and fell back to creating a trivial iOS demo as a sanity-check (which is what let to this thread). I'm happy to report that I have Firebase/Database working on tvOS after following the example provided with firebase-ios-sdk: #10 (comment) |
I wonder if the tvOS bug is related to #2157. Is it possible your project has Otherwise, I can help you try to step through this to debug it. As a very brief overview,
Somewhere along those lines it's failing, it would be great if we could find out where but unfortunately I still can't reproduce it. Here are the code locations for each associated step, if you could try to set breakpoints and follow along to see where it drops off:
I know this system is a little complex (tl;dr - it's needed because an instance of |
@ryanwilson thanks for the details steps, I'll set some breakpoints later today |
Is |
Ahhh, it is not.
|
So, one of these podspecs must be setting
|
CocoaPods should be adding -ObjC automatically. |
So it sounds like the situation is:
|
Yep. I should have remembered CocoaPods/CocoaPods#7946 sooner when you said you were doing tvOS. |
Would it be reasonable to add |
Just for some perspective, our team is actually still on cocoapods 1.4.0 (I use a more up-to-date version for personal / one-off projects). Why would we do this? It turns out that different versions of cocoapods, despite being essentially feature compatible, will produce very different Xcode project files. If you have two team members using different versions of cocoapods, the result is that a tiny change to the pod file file will cause a giant amount of noise in the PR if a different version of cocoapods is used. So there's a pressure on teams to all stick to the same version of cocoapods. The easiest way to ensure everyone is on the same page is to add a Gemfile to the project which specifies a particular version of cocoapods. At that point, keeping the team up-to-date with the latest version of cocoapods becomes a maintenance task, which competes with all of the other priorities of the team, and if it ain't broke... This leads me to suspect there may be a lot of teams who are using an older version of cocoapods. |
Just for reference, here is how we avoid having to type We have a script called We then symlink this Here is the #!/usr/bin/env python
# A wrapper for 'pod' which detects if it should run 'bundle exec pod' or
# use the system 'pod' command, based on the presence of a 'Gemfile'.
# If a Gemfile exists in any directory above pwd, 'bundle exec pod' should
# be used. Otherwise, the system 'pod' is used.
# Expected behavior:
# $ pwd
# /Users/foo/github/some_repo
# $ pod --version
# 1.4.0
# $ cd /tmp
# $ pod --version
# 1.5.3
import os
import sys
def gemfile_exists():
# Ascend up the directory tree looking for a Gemfile.
gempath = 'Gemfile'
while True:
if os.path.exists(gempath):
return True
else:
if os.path.abspath(gempath) == '/Gemfile':
return False
else:
gempath = '../' + gempath
continue
if __name__ == "__main__":
if gemfile_exists():
cmd = ['bundle', 'exec', 'pod'] + sys.argv[1:]
else:
scriptdir = os.path.dirname(__file__)
pathchunks = os.environ["PATH"].split(':')
if scriptdir in pathchunks:
os.environ["PATH"] = ':'.join(
filter(lambda x: x != scriptdir, pathchunks)
)
else:
# We can't find an exact match in $PATH, so fall back to the
# alternate strategy of chopping one leading component from $PATH
# and recursing.
# (To instead chop a trailing component, change '[1:]' to '[:1]')
os.environ["PATH"] = ':'.join(pathchunks[1:])
cmd = ['pod'] + sys.argv[1:]
os.execvp(cmd[0], cmd) |
@pepasflo Thanks for sharing your CocoaPods workflow and all of your input on this bug! One approach we use to manage CocoaPods and Xcode project files is to simplify them by checking them in after running I'm hesitant to add workarounds and extra complexity to our implementation to work around a fixed CocoaPods bug, especially for tvOS which is still community supported for us. I'd prefer to improve the documentation to address it and happy to accept such PRs. |
Sounds good, thanks everyone for your prompt and friendly responses on this, especially considering my initial bad attitude. |
^ How could this possibly be happening? you might ask
Oh, that's why.
Guys, this is extremely uncool. I've just wasted several hours tearing my hair out over why the completion block in
observeSingleEvent
is never getting executed, only to discover that my DB ref (which "can't be nil") was nil the entire time.I'd invite you to take a moment and try to appreciate how unbelievably frustrating this is. With this single line of code, you have ensured a terrible on-boarding experience for new developers: it's not that they hit an error, or hit a crash, its that nothing happens at all, and they have no idea why, and you are actively derailing their intuition about where the problem might be.
Please, for the love of $DEITY, don't use
NS_ASSUME_NONNULL_BEGIN
.The text was updated successfully, but these errors were encountered: