Эти части
video?.exportFilterVideo(videoComposition: avVideoComposition , completion: { (url) in
Merge(config: .standard).overlayVideo(video: filterVideoAsset, overlayImage: videoImage, completion: { (finalVideoUrl) in
делают основной поток очень занятым. поэтому вам нужна фоновая очередь, например
func handleAddToStory() {
print("Attempting to add to story")
// hide the color slider so we can return the image of the tapView that contains the text field if they added one
colorSlider.isHidden = true
let videoImage = self.imageWithView(inView: self.tapView)
colorSlider.isHidden = false
self.dismiss(animated:false, completion: nil)
self.videoPlayer?.replaceCurrentItem(with: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7 ) {
video?.exportFilterVideo(videoComposition: avVideoComposition , completion: { (url) in
if let videoImage = videoImage {
let filterVideoAsset = AVAsset(url: url! as URL)
// Now merge the filtered video with tapView image which will contain the textfield if the user added one
Merge(config: .standard).overlayVideo(video: filterVideoAsset, overlayImage: videoImage, completion: { (finalVideoUrl) in
upload(finalVideoUrl! as URL)
}, progressHandler: { _ in })
} else {
upload(url! as URL)
}
})
}
}
func upload(_ url:URL) {
DispatchQueue.global().async {
let dateFormatter = ISO8601DateFormatter()
let timeStamp = dateFormatter.string(from: Date())
let uid = User.current.uid
let storageRef = Storage.storage().reference().child("event_stories").child(self.eventKey).child(uid).child(timeStamp + ".mp4")
StorageService.uploadVideo(url, at: storageRef) { (downloadUrl) in
guard let downloadUrl = downloadUrl else {
return
}
let videoUrlString = downloadUrl.absoluteString
print(videoUrlString)
PostService.create(for: self.eventKey, for: videoUrlString)
}
}
}
Посмотрите на функцию строкового соединения.
<xsl:value-of select="string-join(/path/to[1]/nodes/text(), ' ')" />