My application read the data correctly and all things work as needed but when I run it on my iphone the data is not shown like it is empty or null, I checked the code try to figure out why but I did not find out the problem. and when I read the data directly in " FirstScreenViewController" View Controller the data is appear so I do know exactly where is the problem any help please My code:
//
// DataManager.swift
// Aqra3
//
// Created by Mahmoud Abdelaziz on 14/01/2023.
//
import UIKit
import FirebaseFirestore
class DataManager {
static let shared = DataManager()
var delegate: DataManagerDelegate?
//var dataCache = [String: Any]() // for screen 1 [0] is the title
let currentDateTime = Date()
var db: Firestore!
var db2: Firestore!
var db3: Firestore!
//var db4: Firestore!
//var dailyAdvice = String()
var screenOneBody = String()
var screenOneTitle = String()
var screenTwoBody = String()
var screenTwoTitle = String()
var screenThreeBody = String()
var screenThreeTitle = String()
//private init() {}
func fetchDataFromFirestore(date: String) {
let settings = FirestoreSettings()
Firestore.firestore().settings = settings
db = Firestore.firestore()
db2 = Firestore.firestore()
db3 = Firestore.firestore()
//db4 = Firestore.firestore()
//let topicDay = String(self.currentDateTime.formatted(date: .abbreviated, time: .omitted))// exp Jan 3, 2023
let screenOne = db.collection("Screen1").document(date)
screenOne.getDocument{ (document, error) in
if let document = document, document.exists {
self.screenOneBody = document.get("Body")! as! String
self.screenOneTitle = document.get("Title")! as! String
print("Screen One Body: \(self.screenOneBody) \n")
print("Screen One Title: \(self.screenOneTitle) \n")
print("Data: \(date) \n")
// DispatchQueue.main.async {
// self.delegate?.dataDidUpdate()
// }
let screenTwo = self.db2.collection("Screen2").document(date)
screenTwo.getDocument{ (document, error) in
if let document = document, document.exists {
self.screenTwoBody = document.get("Body")! as! String
self.screenTwoTitle = document.get("Title")! as! String
print("Screen Two Body: \(self.screenTwoBody) \n")
print("Screen Two Title: \(self.screenTwoTitle) \n")
print("Data: \(date) \n")
let screenThree = self.db3.collection("Screen3").document(date)
screenThree.getDocument { (document, error) in
if let document = document, document.exists {
self.screenThreeBody = document.get("Body")! as! String
self.screenThreeTitle = document.get("Title")! as! String
print("Screen Three Body: \(self.screenThreeBody) \n")
print("Screen Three Title: \(self.screenThreeTitle) \n")
print("Data: \(date) \n")
} else {
print("Document does not exist")
print("Data: \(date)")
}
}
}
}
}
}
}
}
protocol DataManagerDelegate {
func fetchDataFromFirestore(date: String)
func dataDidUpdate()
}
//
// FirstScreenViewController.swift
// Aqra3
//
// Created by Mahmoud Abdelaziz on 01/01/2023.
//
import UIKit
import SwiftUI
import FirebaseFirestore
class FirstScreenViewController: UIViewController, DataManagerDelegate {
func fetchDataFromFirestore(date: String) {
DataManager.shared.fetchDataFromFirestore(date: date)
changeTheBody()
DataManager.shared.delegate?.dataDidUpdate()
}
//var newDateFromMenu = SideMenuViewController()
var db: Firestore!
let currentDateTime = Date()
let refreshControl = UIRefreshControl()
var refreshTimer = Timer()
@IBOutlet weak var FirstScreenTextView: UITextView!
@IBOutlet weak var firstScreenTitle: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true // hide the back button
let settings = FirestoreSettings()
Firestore.firestore().settings = settings
db = Firestore.firestore()
//self.navigationController!.navigationBar.tintColor = UIColor.red // this if you want to cahnge the navigationBar color without change the global tint color
//DataManager.shared.fetchDataFromFirestore()
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .right
self.view.addGestureRecognizer(swipeLeft)
DataManager.shared.delegate = self
//let topicDay = String(self.currentDateTime.formatted(date: .abbreviated, time: .omitted))// exp Jan 3, 2023
//DataManager.shared.fetchDataFromFirestore(date: topicDay)
changeTheBody()
refreshTimer = Timer.scheduledTimer(timeInterval: 0.0, target: self, selector: #selector(changeTheBody), userInfo: nil, repeats: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
refreshTimer.invalidate()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
refreshTimer = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(changeTheBody), userInfo: nil, repeats: true)
}
@objc func changeTheBody() {
FirstScreenTextView.text = "\(DataManager.shared.screenOneBody)"
//FirstScreenTextView.semanticContentAttribute = .forceRightToLeft
let style = NSMutableParagraphStyle()
style.lineSpacing = 10 // adjust line spacing as needed
style.baseWritingDirection = .rightToLeft
style.alignment = .justified
let attributes = [ NSAttributedString.Key.paragraphStyle: style]
FirstScreenTextView.attributedText = NSAttributedString(string: FirstScreenTextView.text, attributes: attributes)
FirstScreenTextView.font = UIFont.systemFont(ofSize: 20)
FirstScreenTextView.textColor = UIColor.white
firstScreenTitle.textColor = UIColor.white
firstScreenTitle.text = "\(DataManager.shared.screenOneTitle)"
refreshControl.endRefreshing()
}
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == UISwipeGestureRecognizer.Direction.right {
performSegue(withIdentifier: "fromFirstScreenToMainScreen", sender: self)
}
}
/* override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToResult" {
let destinationVC = segue.destination as! SideMenuViewController
}
}*/
func dataDidUpdate() {
changeTheBody()
}
}
//
// AppDelegate.swift
// AQRA3
//
// Created by Mahmoud Abdelaziz on 01/01/2023.
//
import UIKit
import FirebaseCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
let currentDateTime = Date()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let topicDay = String(self.currentDateTime.formatted(date: .abbreviated, time: .omitted))// exp Jan 3, 2023
FirebaseApp.configure()
DataManager.shared.fetchDataFromFirestore(date: topicDay)
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
CodePudding user response:
I think I know what is happening here.
When you read the data in your AppDelegate
, it gets read, and the delegate callback (self.delegate?.dataDidUpdate()
) in the DataManager
occurs before you set your FirstScreenViewController
view controller as the DataManager
's delegate (on the line DataManager.shared.delegate = self
). At this point the DataManager
's delegate is nil
, so you do not receive the callback in your view controller.
The correct way to ensure that you always get the delegate callback would be that you set the DataManager
's delegate
before you execute the fetchDataFromFirestore(date: String)
call.
If this helps you, please consider marking this as the answer.
CodePudding user response:
I know the problem The data is saved in the firestore with the date in this format Jan 10, 2023 Jan 24, 2023 and so on when get the date i was test getting it with the simulator and the format was the same MMM DD, YYYY, but when turn on the physical device the format was DD MMM, YYYY so I add a code to force the format to be MMM DD, YYYY
let topicDay = String(self.currentDateTime.formatted(date: .abbreviated, time: .omitted) )// exp Jan 3, 2023
let dateString = topicDay
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"
let date = dateFormatter.date(from: dateString)
dateFormatter.dateFormat = "MMM dd, yyyy"
let newDateString = dateFormatter.string(from: date!)