7

I have tried to debug this but to no avail.

Basically when I segue from the first view controller to the second view controller the screen goes black momentarily. The code performs as I want it to but the screen going black is a bit of a pain for me.

Here is the code:

The segue from the first page:

func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation) {
        self.performSegue(withIdentifier: "goToSecond", sender: self)
    }

second view controller:

override func viewDidLoad() {
    super.viewDidLoad()
    self.loadDataFromFirebase()
}

first function:

  func loadDataFromFirebase() {
           let db = Firestore.firestore()
           db.collection(restaurauntName).getDocuments { (snapshot, err) in
              if let err = err {
                 print("Error getting documents: \(err)")
                 return
              } else {
                 for document in snapshot!.documents {
                    let name = document.get("Name") as! String
                    let description = document.get("Description") as! String
                    self.names.append(name)
                    self.descriptions.append(description)
                 }
                 self.setupImages() //safe to do this here as the firebase data is valid
                 self.collectionView?.reloadData()
              }
           }
        }

this function sets up the page layout

func setupImages(){
        self.pages = [
            Page(imageName: self.imagesOne, headerText: names[0], bodyText: descriptions[0]),

            Page(imageName: self.imagesTwo, headerText: names[1], bodyText: descriptions[1]),

            Page(imageName: self.imagesThree, headerText: names[2], bodyText: descriptions[2]),

            Page(imageName: self.imagesFour, headerText: names[3], bodyText: descriptions[3]),

            Page(imageName: self.imagesFive, headerText: names[4], bodyText: descriptions[4]),
        ]

        self.collectionView?.backgroundColor = .white
        self.collectionView?.register(PageCell.self, forCellWithReuseIdentifier: "cellId")

        self.collectionView?.isPagingEnabled = true
    }

This sets up the page control

lazy var pageControl: UIPageControl = {
    let pc = UIPageControl()
    pc.currentPage = 0
    pc.numberOfPages = 5
    pc.currentPageIndicatorTintColor = .red
    pc.pageIndicatorTintColor = .gray
    return pc
}()

swiping controller extension:

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return pages.count

    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! PageCell

        let page = pages[indexPath.item]
        cell.page = page
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: view.frame.height)
    }

Please let me know if I have to add anything else! any help is welcome

here is a youtube clip of the problem:

https://www.youtube.com/watch?v=vQGiw3Jd9pM

I have since found that when I comment out the firebase method the problem goes away.

Hamed
  • 5,867
  • 4
  • 32
  • 56
mick1996
  • 516
  • 9
  • 31
  • where do you call mapView(…) ? – claude31 Jan 27 '20 at 22:09
  • @claude31 thank you for looking at my question, mapView() is called on the previous view controller. The segue works, it just goes black before completion of segue :( – mick1996 Jan 28 '20 at 00:25
  • What is the segue type ? – claude31 Jan 28 '20 at 09:52
  • @claude31 just the regular show segue – mick1996 Jan 28 '20 at 15:10
  • Who is the second controller pointed at by "goToSecond" segue ? How is the presentation defined in this second controller (automatic ? full screen ?). What is the default backgroundcolor of the view ? May be you could change this in IB to avoid the black hole effect ? – claude31 Jan 28 '20 at 15:31
  • "goToSecond" is the identifier of the segue from 1st VC to 2nd VC. it it a full screen presentation. the background color is white . I think the problem lies in the way the view is displayed for some reason. Thank you for your comment – mick1996 Jan 28 '20 at 16:52
  • @claude31 I have added a youtube clip of the issue :) – mick1996 Jan 28 '20 at 17:24
  • Very clear and really problematic. You did not tell and show the code for the second controller, at least what deals with its viewDidload. – claude31 Jan 28 '20 at 17:33
  • I'm not sure I understand @claude31 everything is from the second view controller apart from mapView() function – mick1996 Jan 28 '20 at 17:36
  • Sorry, I missed it. Could you put self.loadDataFromFirebase() in another thread (may be some parts will need to be in main thread) – claude31 Jan 28 '20 at 17:41
  • @claude31 no bother :) I think thats what I'm struggling with. Im not sure how to do that – mick1996 Jan 28 '20 at 17:49
  • Could just try in viewDidLoad. DispatchQueue.global().async { self.loadDataFromFirebase() }. Take care, I don't know how loadData works and if it needs to work in main thread. – claude31 Jan 28 '20 at 20:25
  • @claude31 tried that, been working on it for a few hours now and nothing yet :( – mick1996 Jan 28 '20 at 20:40
  • Any other ideas @claude31 – mick1996 Jan 30 '20 at 01:42
  • May be not a good idea, but… Instead of performSegue, try to instantiate. let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil) let controller = storyboard.instantiateViewController(withIdentifier: "someViewController") self.present(controller, animated: true, completion: nil) – claude31 Jan 30 '20 at 16:51
  • @claude31 I tried that and still no solution :( – mick1996 Feb 11 '20 at 17:49
  • 1
    *comment out the firebase method the problem goes away.* this issue is unrelated to Firebase. The reason it fixes the issue is because it's also commenting out `self.setupImages()` which may be where the problem is. Add a breakpoint here `self.collectionView?.backgroundColor = .white` and run the app. It will stop on that line. Is the screen black? If no, then step to the next line and see, rinse repeat until you find the line that makes it go black. If it goes black before that break then the issue is prior to that line. Add a breakpoint here 'self.loadDataFromFirebase()` and try again. – Jay Feb 11 '20 at 18:28
  • @Jay I will try that now! thank you for having another look! – mick1996 Feb 11 '20 at 18:40
  • did you added white background color code in your viewdidload? – Shanu Singh Feb 17 '20 at 12:58
  • @ShanuSingh nope. The problem was the order in which the code was being called. For some reason the Firebase function caused the thread to overload and go black. Then by repositioning where it was called I was able to alleviate the problem. – mick1996 Feb 17 '20 at 15:44

2 Answers2

2

I have solved the problem! the problem was the order in which the functions were being called.

I realised not that the page was being set up too fast for firebase so I now call the function earlier! in the view will appear

override func viewWillAppear(_ animated: Bool) {
        print("Done")
        super.viewWillAppear(animated)

        self.loadDataFromFirebase()
}

Thanks to all who helped!

mick1996
  • 516
  • 9
  • 31
  • Well... While this 'fixed' the issue for now, it will not be a long term solution. Being 'too fast for Firebase' is not the actual issue as Firebase has absolutely nothing to do with your UI or the screen going black. Go with it for now but loop back around when the issue pops up again as you'll need to revisit the code. – Jay Feb 12 '20 at 18:22
  • @Jay thank you again for your follow up and advice! I have tested it by reducing the internet quality and speeds and also by overloading the phones RAM and it seem to work fine. Do you think this means that the problem is fixed or have I just put a band aid on the problem? if so can you suggest any other solutions? or ways of testing? thanks – mick1996 Feb 12 '20 at 20:08
  • Big time band aid, which just so happens to have fixed the issue. Firebase and UI are totally unrelated and it would be 'impossible' for any firebase API call to make your screen go black. – Jay Feb 12 '20 at 20:53
  • Any suggestions on what I should do to fix it? thanks for help again! – mick1996 Feb 12 '20 at 20:55
  • 1
    Not at the moment but my guess is that you're sizing a collection view as the size of the entire screen at some point so it's 'covering' the viewController. Maybe here `return CGSize(width: view.frame.width, height: view.frame.height)` is something to look at. Again, breakpoints are your friend and going to be the only way to nail it down. – Jay Feb 12 '20 at 21:13
0

it seems your loadDataFromFirebase() method is taking a long time to execute on the main thread causing it to hung. Move your fetch to a background thread and update your UI once the data has been fetched in the meantime display a loading indicator or something of the sorts. Try:

func loadDataFromFirebase() {
    DispatchQueue.global(qos: .userInitiated).async { [weak self] in 
        // Fetch and convert data
        let db = Firestore.firestore()
        ...
        DispatchQueue.main.async {
             // Update your UI components with the data here
             self.setupImages()
             self.collectionView?.reloadData()
        }
    }
}
Valentin
  • 3,272
  • 1
  • 14
  • 22
  • Hi there, Thank you for taking the time to view my question. unfortunately that does not solve it :( if you have any other ideas id love to try them! I think the solution is along the lines of your answer! I just cant figure it out – mick1996 Feb 11 '20 at 18:14
  • 1
    @mick1996 This answer is not correct. Firebase executes all UI calls on the Main thread and **all network calls on a background thread**. It will never cause the UI to slow down. You will not need a DispatchQueue within a Firebase closure or assign calls on different threads nor call firebase functions on other threads - it handles that itself. See [this question](https://stackoverflow.com/questions/39178165/firebase-asynchronous-function-whats-in-the-background-queue-and-whats-not) and the 'Firebase Frank' answer. – Jay Feb 11 '20 at 18:36