This is the tableViewController streaming video when user taps on a row. Just Succeeded to display "name" and "lessonName" in the tableviewcontroller but it finds nil while unwrapping images and I think it will find nil while unwrapping video file "fileURL"
and even video player. Any help is appreciated, thank you in advance.
import UIKit
import AVKit
import AVFoundation
import FirebaseFirestore
import Combine
class ListOfVideoLessonsTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let pinchGesture = UIPinchGestureRecognizer()
private var viewModel = VideosViewModel()
private var cancellable: AnyCancellable?
var player = AVPlayer()
var playerViewController = AVPlayerViewController()
@IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.viewModel.fetchData()
self.title = "Video Lessons"
table.delegate = self
table.dataSource = self
// Do any additional setup after loading the view.
cancellable = viewModel.$videos.sink { _ in
DispatchQueue.main.async{
self.table.reloadData()
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("videos count = ", viewModel.videos.count)
return viewModel.videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let video = viewModel.videos[indexPath.row]
tableView.tableFooterView = UIView()
//configure cell
cell.textLabel?.text = video.name
cell.detailTextLabel?.text = video.lessonName
cell.accessoryType = .disclosureIndicator
let imageName = UIImage(named: video.imageName)
cell.imageView?.image = imageName!.withRenderingMode(.alwaysTemplate)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor(named: "VideoLessonsCellHighlighted")
cell.selectedBackgroundView = backgroundView
cell.textLabel?.font = UIFont(name: "Helvetica-Bold", size: 14)
cell.detailTextLabel?.font = UIFont(name: "Helvetica", size: 12)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
playVideo(at: indexPath)
}
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.contentView.backgroundColor = UIColor(named: "VideoLessonsCellHighlighted")
cell.textLabel?.highlightedTextColor = UIColor(named: "textHighlighted")
cell.detailTextLabel?.highlightedTextColor = UIColor(named: "textHighlighted")
}
}
func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.contentView.backgroundColor = nil
}
}
func playVideo(at indexPath: IndexPath){
let selectedVideo = viewModel.videos[indexPath.row]
let url = URL(string: selectedVideo.fileURL)
player = AVPlayer(url: url!)
playerViewController.player = player
self.present(playerViewController, animated: true, completion: {
self.playerViewController.player?.play()
})
}
}
This is the Struct of the video files.
import Foundation
struct Video {
var name: String
var imageName: String
var lessonName: String
var fileURL: String
}
This is the viewModel
import Foundation
import FirebaseFirestore
class VideosViewModel: ObservableObject {
@Published var videos = [Video]()
private var db = Firestore.firestore()
func fetchData() {
db.collection("videos").addSnapshotListener { [self] (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No Documents")
return
}
self.videos = documents.map { (queryDocumentSnapshot) -> Video in
let data = queryDocumentSnapshot.data()
let name = data["name"] as? String ?? ""
let imageName = data["imageName"] as? String ?? ""
let lessonName = data["lessonName"] as? String ?? ""
let fileURL = data["fileURL"] as? String ?? ""
videos.append(Video(name: name, imageName: imageName, lessonName: lessonName, fileURL: fileURL))
print(data)
return Video(name: name, imageName: imageName, lessonName: lessonName, fileURL: fileURL)
}
}
}
}
This is what throws when user taps the row now. Also it is interesting why it shows "video count = 0" four times, then it shows "video count = 2 three times"? Am I calling data not in proper place in the code or it is the result of downloading timing of the data?
videos count = 0
videos count = 0
videos count = 0
["lessonName": Lesson Name, "name": Name 1, "fileURL": gs://tff-sample.appspot.com/Video Lessons/mixkit-hands-of-a-man-playing-on-a-computer-43527.mp4, "imageName": gs://tff-sample.appspot.com/Video Images/1024x1024.png]
["fileURL": gs://tff-sample.appspot.com/Video Lessons/mixkit-meadow-surrounded-by-trees-on-a-sunny-afternoon-40647.mp4, "lessonName": Lesson Name, "imageName": gs://tff-sample.appspot.com/Video Images/1024x1024.png, "name": Name 2]
videos count = 2
videos count = 2
videos count = 2
TFF_Sample/ListOfVideoLessonsTableViewController.swift:72: Fatal error: Unexpectedly found nil while unwrapping an Optional value
2022-09-12 12:24:04.606689+0400 TFF Sample[12286:90358] TFF_Sample/ListOfVideoLessonsTableViewController.swift:72: Fatal error: Unexpectedly found nil while unwrapping an Optional value