I'm trying to push a modal from the SceneDelegate. It all works well until the modal push runs.
I'm gettin the error below, and Xcode says that the variables imagePreview and DownloadURL are nil. Yes the variables are loaded from firebase, as if I print them it works.
2020-10-23 02:18:20.277808+0200 MyApp[30028:568894] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file MyApp/DownloadViewController.swift, line 29
func pushFile(id: String) {
self.window?.rootViewController = DownloadViewController()
ref = Database.database().reference(withPath: "files")
ref.child(id).observeSingleEvent(of: .value, with: { [self] (snapshot) in
let value = snapshot.value as? NSDictionary
let preview = value?["a"] as? String ?? ""
let downloadURL = value?["d"] as? String ?? ""
if let tabBarController = window?.rootViewController! as? UIViewController { //use of unresolved identifier 'window'
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = storyboard.instantiateViewController(withIdentifier: "download") as? DownloadViewController {
vc.imagePreview = preview
vc.downloadURL = downloadURL
tabBarController.present(vc, animated: true)
}
}
})
}
Related
i created a sign in with google feature, and everything is working with the signing in with the firebase and authentication. my problem is that after a successful sign in i want the app to move to a differnent page/controller from the app delegate.
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let viewController: SigninViewController = storyboard.instantiateViewController(withIdentifier: "GoogleTabController") as! SigninViewController;
// Then push that view controller onto the navigation stack
let rootViewController = self.window!.rootViewController as! UINavigationController;
rootViewController.pushViewController(viewController, animated: true);
is giving me an error that reads "could not cast value of type uitabbarcontrller to signinViewcontroller"
here is my full code:
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
let number = Int.random(in: 0..<100)
let numberString = String(number)
let db = Firestore.firestore()
let googleName = user.profile.name
let googleEmail = user.profile.email
let googleUsername = user.profile.name+numberString
let country = ""
let bio = ""
let profImg = user.profile.imageURL(withDimension: 100)?.absoluteString
let password = ""
Auth.auth().signInAndRetrieveData(with: credential) { (authResulft, error) in
if let error = error{
print(error)
}else{
let userid = Auth.auth().currentUser!.uid
db.collection("users").whereField("uid", isEqualTo: userid).getDocuments(){querySnapshot, error in
if let error = error {
print(error.localizedDescription)
}else
{
if querySnapshot!.isEmpty{
db.collection("users").document(userid).setData([
"name": googleName!,
"username": googleUsername,
"email": googleEmail!,
"password": password,
"uid": userid,
"country": country,
"bio": bio,
"profileImage": profImg!,
]) { err in
if err != nil {
} else {
print("logged in success and db stored")
//below code doesnt work
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let viewController: SigninViewController = storyboard.instantiateViewController(withIdentifier: "GoogleTabController") as! SigninViewController;
// Then push that view controller onto the navigation stack
let rootViewController = self.window!.rootViewController as! UINavigationController;
rootViewController.pushViewController(viewController, animated: true);
}
}
}else{
//here perform segue
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let viewController: SigninViewController = storyboard.instantiateViewController(withIdentifier: "GoogleTabController") as! SigninViewController;
// Then push that view controller onto the navigation stack
let rootViewController = self.window!.rootViewController as! UINavigationController;
rootViewController.pushViewController(viewController, animated: true);
}
}
}
}
}
}
The problem is here
let viewController: SigninViewController = storyboard.instantiateViewController(withIdentifier: "GoogleTabController") as! SigninViewController;
GoogleTabController is a tabViewController not SigninViewController you need to use
let viewController = storyboard.instantiateViewController(withIdentifier: "GoogleTabController")!
I am trying to go to "inbox" tab when I clicked on the notification.
This is the notificationManager:
func didReceiveNotification(notif: [AnyHashable : Any]) {
print("notification... \(notif)")
guard let msgData = notif["gcm.notification.messageData"] as? String else {
return
}
print("msgData: \(msgData)")
CommandManager.shared.processNotification(msgData)
}
This is the commandManager:
func processNotification(_ commands: String) {
var dict:[String:Any] = [:]
dict = dict.convertToDictionary(text: commands) ?? [:]
print("dict \(dict)")
sendMessageToFirestore(data: dict)
let inbox = EngageViewController()
//present the inbox tab
}
Use rootViewController
func processNotification(_ commands: String) {
var dict:[String:Any] = [:]
dict = dict.convertToDictionary(text: commands) ?? [:]
print("dict \(dict)")
sendMessageToFirestore(data: dict)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "inboxPage") as! UIViewController
UIApplication.shared.keyWindow?.rootViewController = viewController
}
Edit
If it's a UITabBarController, use:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
viewcontroller.selectedIndex = 1 //index of your inbox
UIApplication.shared.keyWindow?.rootViewController = viewController
If the initial view of app is TabBarController then you can do something like in
AppDelegate.swift
guard let tabBarController = self.window?.rootViewController as? UITabBarController else {
return
}
so,
tabBarController.selectedIndex = 1 //Whatever the index of inbox is
I am trying to check the null condition for one of the dictionaries of json response.But when i checking the condition, I am getting an error like "Binary operator '==' cannot be applied to operands of type '[String : Any]' and 'JSON'".I am getting this error at the line of if !(chattt == JSON.null).If any one helps me to solve this,would be great.Thanks in advance.
let acce:String = UserDefaults.standard.string(forKey: "access-tokenn")!
print(acce)
let headers:HTTPHeaders = ["Authorization":"Bearer \(acce)","Content-Type":"application/X-Access-Token"]
print((Constants.Chatlistsearch)+(idd))
Alamofire.request((Constants.Chatlistsearch+idd), method: .get, encoding: URLEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success:
//print(response)
if response.result.value != nil{
var maindictionary = NSDictionary()
maindictionary = response.result.value as! NSDictionary
// print(maindictionary)
var chat:Dictionary = maindictionary.value(forKey: "data") as! [String:Any]
// print(chat)
var chatt:Dictionary = chat["user"] as! [String:Any]
// print(chatt)
var chattt:Dictionary = chat["chat"] as! [String:Any]
print(chattt)
if !(chattt == JSON.null) {
let viewc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ChatViewController") as? ChatViewController
self.navigationController?.pushViewController(viewc!, animated: true)
}else{
print("Find Action")
}
// self.data = [String(stringInterpolationSegment: chatt["unique_id"])]
// print(self.data)
}
break
case .failure(let error):
print(error)
}
}
}
You can do it this way
if let chattt = chat["chat"] as? [String:Any] {
//It's available. Execute further tasks
} else {
//It's nil or chat["chat"] type is not dictionary.
}
You can either do it using guard.
guard let chattt = chat["chat"] as? [String:Any] else {
//Using this, the further code will never execute as implemented force return here
return
}
if any issue please let me know.
do the following
guard let chattt = chat["chat"] as? [String:Any] else {
let viewc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ChatViewController") as? ChatViewController
self.navigationController?.pushViewController(viewc!, animated: true)
return
}
I am getting blank User even though i am setting the value in NSUSERdefault.Its working with Lock mode but same code is not working for timeout of App (5 min) User is vcLogin.usernameTxt?.text = uname is coming blank even NSUserDefaults.standardUserDefaults().objectForKey("Username") as! String has value
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vcLogin = storyboard.instantiateViewControllerWithIdentifier("Login") as! LoginViewController
var uname:String!
if (NSUserDefaults.standardUserDefaults().objectForKey("Username") != nil) {
print("username =\(NSUserDefaults.standardUserDefaults().objectForKey("Username"))")
uname = NSUserDefaults.standardUserDefaults().objectForKey("Username") as! String
NSUserDefaults.standardUserDefaults().synchronize()
}else{
uname = ""
}
let navVC = self.window?.rootViewController as? UINavigationController
var arr=[UIViewController]()
arr = (navVC?.viewControllers)!
if ((arr.last?.isKindOfClass(LoginViewController)) != nil) {
arr.append(vcLogin)
navVC?.viewControllers = arr
print("name=\(uname)")
//if uname != nil {
vcLogin.usernameTxt?.text = uname
//}
}
}
}
let theUsername = NSUserDefaults.standardUserDefaults().objectForKey("Username")!
print("username =\(theUsername)")
By the way, why do you use Swift 2?
I have begun building an app that lets a user sign up and create a family. Right now I am downloading the data for the user from the log in screen and, from the appDelegate if the user is already logged in. However, when the user data is downloaded from the appDelegate I get nil values.
Whats weird is that I have the following written in each of my three view controllers(controlled by a tab controller):
var user: User? {
didSet {
print(user!.name!)
}
}
When the data eventually downloads from the appDelegate the correct name is printed. However, trying to use the user variable at any other time gives nil.
Also, when the data is downloaded from the log in screen it works perfectly. Very confused about this and would hugely appreciate any help. Thanks in advance.
I figured out what was wrong. Nothing to do with firebase.
While in the app delegate after downloading the user data, I tried to set the properties of the viewControllers in my tabViewController. What I actually did was create a new instance of each view controller, set its properties(which is why the didSet property observer fired) but then when setting the rootViewController I created a new instance of the tabController which I think then created new instances of the three viewControllers.
This is what the old code was in the appDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
if let user = FIRAuth.auth()?.currentUser {
downloadUserData(user)
self.window?.rootViewController = storyBoard.instantiateViewControllerWithIdentifier("Home")
} else {
window?.rootViewController = storyBoard.instantiateViewControllerWithIdentifier("SignIn")
}
return true
}
func downloadUserData(user: FIRUser) {
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().queryEqualToValue(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
for child in snapshot.children {
if let name = child.value!["name"] as? String, let familyID = child.value!["signedInTo"] as? String {
self.user = User(uid: user.uid, name: name)
ref.child("families").queryOrderedByKey().queryEqualToValue(familyID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
for child in snapshot.children {
if let name = child.value!["name"] as? String {
self.family = Family(uid: familyID, name: name)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let tabVC = storyBoard.instantiateViewControllerWithIdentifier("Home") as? TabBarViewController
tabVC?.user = self.user
tabVC?.family = self.family
let choresNav = tabVC?.viewControllers![0] as? UINavigationController
let choresVC = choresNav?.topViewController as? ChoresViewController
choresVC?.user = self.user
choresVC?.family = self.family
}
}
})
}
}
})
}
This is the appDelegate now, along with a custom TabBarViewController:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
if let user = FIRAuth.auth()?.currentUser {
downloadUserData(user)
} else {
window?.rootViewController = storyBoard.instantiateViewControllerWithIdentifier("SignIn")
}
return true
}
func downloadUserData(user: FIRUser) {
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().queryEqualToValue(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
for child in snapshot.children {
if let name = child.value!["name"] as? String, let familyID = child.value!["signedInTo"] as? String {
self.user = User(uid: user.uid, name: name)
ref.child("families").queryOrderedByKey().queryEqualToValue(familyID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
for child in snapshot.children {
if let name = child.value!["name"] as? String {
self.family = Family(uid: familyID, name: name)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let tabVC = storyBoard.instantiateViewControllerWithIdentifier("Home") as? TabBarViewController
tabVC?.user = self.user
tabVC?.family = self.family
self.window?.rootViewController = tabVC
}
}
})
}
}
})
}
TabBarController:
var user: User?
var family: Family?
override func viewDidLoad() {
super.viewDidLoad()
print(user?.name)
print(family?.name)
let navVC = self.viewControllers![0] as? UINavigationController
let itemsNav = self.viewControllers![1] as? UINavigationController
let leaderNav = self.viewControllers![2] as? UINavigationController
let choresVC = navVC!.topViewController as? ChoresViewController
let itemsVC = itemsNav!.topViewController as? ShoppingListViewController
let leaderVC = leaderNav!.topViewController as? LeaderBoardViewController
choresVC?.user = self.user
choresVC?.family = self.family
itemsVC!.user = self.user
itemsVC!.family = self.family
leaderVC!.user = self.user
leaderVC!.family = self.family
}
The code I have still isn't great but it has solved the problem. Hope it helps some of you out.