Hi all,
I have been facing a problem while loading a file from the firebase storage.
Basically in my code i have a data model which is the file/document (pdf in this case), a manager which goes into the database of Firebase to fetch the object and finally two views, one to list the files fetched and another one to show the document.
I can fetch all the documents with their specific data, pass them to my view and then show the document pdf in another view.
Everything seems correct but the problem comes when opening one of this docs. First, the doc doesn't open at first so you need to close the view and try to open the doc again. Then when i want to open another doc from my list, when i click on it the previous document is shown and not the correct one, so i need to do the same, close the view and click again on the doc to open the correct one.
So at the end what i'm looking for is to open the doc just clicking once but i don't know where is my problem.
List of docs:
1st time:
2nd time:
2nd doc but 1st time:
2nd doc and 2nd time clicking on it:
Here is my code
Model:
struct DocumentoPdf {
let titulo: String
let docUrl: URL?
let id: String
let storageUrl: String
}
Manager which fetches the documents from firebase:
final class DatabaseManager {
[...]
public func getNovedades(completion: @escaping ([DocumentoPdf]) -> Void) {
database.collection("novedades").getDocuments { snapshot, error in
guard let documents = snapshot?.documents.compactMap ({ $0.data() }), error == nil else {
return
}
let novedades: [DocumentoPdf] = documents.compactMap({ dictionary in
guard let id = dictionary["id"] as? String,
let titulo = dictionary["titulo"] as? String,
let docUrlString = dictionary["docUrl"] as? String,
let storageUrl = dictionary["storageUrl"] as? String else {
return nil
}
let novedad = DocumentoPdf(titulo: titulo,
docUrl: URL(string: docUrlString),
id: id,
storageUrl: storageUrl)
return novedad
})
completion(novedades)
}
}
}
First View:
class NovedadesViewControllerViewModel {
let docUrl: URL?
var docData: Data?
init(docUrl: URL?) {
self.docUrl = docUrl
}
}
class NovedadesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, PDFViewDelegate {
private var tableView = UITableView()
private var doc = PDFDocument()
public func configureDocPdf(with viewModel: NovedadesViewControllerViewModel) {
if let data = viewModel.docData {
doc = PDFDocument(data: data)!
}
else if let url = viewModel.docUrl {
// fetch doc & cache
let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
guard let data = data else {
return
}
viewModel.docData = data
DispatchQueue.main.async {
self?.doc = PDFDocument(data: data)!
}
}
task.resume()
}
}
private var novedades: [DocumentoPdf] = []
private func obtenerNovedades() {
DatabaseManager.shared.getNovedades() { [weak self] novedades in
self?.novedades = novedades
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
}
override func viewDidLoad() {
[...]
obtenerNovedades()
[...]
}
[... sections, rows in section...]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let novedad = novedades[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = novedad.titulo
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let novedad = novedades[indexPath.row]
switch indexPath.section {
case 0:
configureDocPdf(with: .init(docUrl: novedad.docUrl))
let lectorPdfView = LectorPdfViewController(doc: self.doc, nameDoc: novedad.titulo)
self.present(lectorPdfView, animated: true, completion: nil)
default:
break
}
}
}
Second View to load the pdf:
class LectorPdfViewController: UIViewController, PDFViewDelegate {
private let navBar = UINavigationBar()
private let pdf = PDFView()
let nameDoc: String
let doc: PDFDocument
init(doc: PDFDocument, nameDoc: String) {
self.doc = doc
self.nameDoc = nameDoc
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(navBar)
view.addSubview(pdf)
pdf.document = self.doc
pdf.delegate = self
let item = UINavigationItem(title: self.nameDoc)
navBar.setItems([item], animated: false)
navBar.barTintColor = .systemBackground
}
override func viewDidLayoutSubviews() {
navBar.frame = CGRect(x: 0,
y: 0,
width: view.frame.size.width,
height: 50)
pdf.frame = CGRect(x: 0,
y: navBar.frame.height,
width: view.frame.size.width,
height: view.frame.size.height - navBar.frame.height)
}
}
Please if someone can help me with this will be fantastic. I hope you understood my code and my problem. Sorry for my bad english
Thank you so much in advance
Post
Replies
Boosts
Views
Activity
Hi,
I am developing an app which has a calendar integrated. This calendar comes from a package called CalendarKit (https://github.com/richardtop/CalendarKit ).
With this calendar you can access to all the events of you mobile integrated calendar and create new ones, modify them, delete, etc. All the events on you mobile calendar are going to be represented here and the same in the other way, everything that you create here will be represented on you mobile calendar.
So the main question is. How can i access to the 'Delete Event' action inside the 'Event Details' view?
I know that i can delete an event programmatically, but i need to "modify" the behavior when clicking on the item 'Delete Event'.
Is there any possible way to access to this item inside event details and when clicking on it do a custom action?.
For example, when clicking i want to:
print a text in the console,
show an alert,
get the EventID of the event deleted,
etc.
Can somebody help me with this??
Thanks a lot in advance.
Hi,
i was following a tutorial and with the same code i have an unknown error.
The idea is to have a table view and inside a cell a collection view with a carrousel of images.
This is the code:
...
private let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(UICollectionViewCell.self,
forCellWithReuseIdentifier: photoCollectionViewCell.identifier)
return collectionView
}()
...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
//cell.backgroundColor = .green
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: photoCollectionViewCell.identifier,
for: indexPath
) as? photoCollectionViewCell else {
fatalError()
}
cell.configure(with: images[indexPath.row])
return cell
}
...
Basically im getting an error in the fatalError() while casting to "photoCollectionViewCell", which is another class that contains the images to show in the carrousel. The error doesn't show any other message than the fatal error message so i have no idea why is failing.
If instead of casting to the "photoCollectionViewCell" i use the two commented lines i get the green cells so at this point im very lost.
It would be very helpful any ideas to solve this. Thanks in advance!!!
PD: sorry for my bad english