Reputation: 766
I would like to modify a string
in another class. This class will then use the variable in a function.
Here is what I've tried so far. I always get an error when unwrapping it: fatal error: unexpectedly found nil while unwrapping an Optional value
. Does anyone have an idea how to change the urlString
(preferably without making it global)? I couldn't find solutions for swift which also involved functions on stackoverflow... If you think I will have to make it global, please let me know!
let videoUrl = "https:...sometestvideo.mov"
videoPlayerView.urlString = videoUrl
var urlString : String?
//setup video player
func setupPlayerView() {
print(urlString)
//URL needed here
if let videoURL = NSURL(string: urlString!){ //here the error occurs
I would like to add that it is very important that the function is called asap in the second class. Therefore I didn't use setupPlayerView(_urlString)
...
Accordingly it currently looks like this (class
2, a UIView):
override init(frame: CGRect){
super.init(frame: frame)
//function below this override init
setupPlayerView()
EDIT:
First of all, thank you for your solution! Nonetheless, one little problem remains (and I thought calling the function immediately would solve it... quite new to swift): namely the video player (which is set up using this function) is now above all the other subviews (one can only see the video covering the entire screen) although the opposite is desired (video using entire screen but subviews cover some parts). I will provide more code below regarding the addition of other subviews (all of these are closures) and the function setting up the view. Is there a way I can keep the videoplayer below all the other subviews (even if it needs to be loaded from a server first)? What would you suggest me to do?
Code below incorporates code from the first answer, but does not necessarily have to start from there
override init(frame: CGRect){
super.init(frame: frame)
setupPlayerView()
//add subview with controls (e.g. spinner)
controlsContainerView.frame = frame
addSubview(controlsContainerView)
//add to subview and center spinner in subview
controlsContainerView.addSubview(activityIndicatorView)
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
//add various subviews
controlsContainerView.addSubview(whiteDummyView)
controlsContainerView.addSubview(userProfilePicture)
//... add further subviews
//enable interaction
controlsContainerView.isUserInteractionEnabled = true
//... set to true for other subviews as well
//function below this override init
defInteractions()
//backgorund color of player
backgroundColor = .black
}
//create controls container view (a closure, like the (most of the) other subviews)
let controlsContainerView: UIView = {
//set properties of controls container view
let controlView = UIView()
controlView.backgroundColor = UIColor(white: 0, alpha: 1)
return controlView
}()
function setupPlayerView()
//setup video player
func setupPlayerView() {
//check URL if can be converted to NSURL
if let urlString = self.urlString, let videoURL = NSURL(string: urlString){
print(urlString)
//player's video
if self.player == nil {
player = AVPlayer(url: videoURL as URL)
}
//add sub-layer
let playerLayer = AVPlayerLayer(player: player)
self.controlsContainerView.layer.addSublayer(playerLayer)
playerLayer.frame = self.frame
//when are frames actually rendered (when is video loaded)
player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
//loop through video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
})
}
}
Upvotes: 0
Views: 77
Reputation: 1668
While navigating to second view controller.
let viewController2 = ViewController2() //viewController2 == class2
viewController2.urlString = videoUrl // anything you want to pass to class2.
navigationController?.pushViewController(viewController2, animated: true)
In your class 2:
var urlString: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(urlString) // use it
setupPlayerView()
}
Your func:
func setupPlayerView() {
//check URL if can be converted to NSURL
if NSURL(string: urlString) != nil{
print(urlString)
}
}
Upvotes: 0
Reputation: 4040
Without too much context about the relationship between your classes, looks like a potentially good solution is to use a property observer pattern.
class Class2 {
var urlString: String? {
didSet {
setupPlayerView()
}
}
override init(frame: CGRect){
super.init(frame: frame)
setupPlayerView()
}
func setupPlayerView() {
if let urlString = self.urlString, let videoURL = NSURL(string: urlString) {
// do stuff here
}
}
}
Upvotes: 1