iOS 13 adds a trim. prefix when selecting a file from Photos:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/trim.DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
Before iOS-13 was like this:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
This is an issue when passing the file URL to alamofire to upload the file to a backend server. It causes an "unknown error" and the upload fails. Perhaps alamofire is having trouble with that little prefix?
Is there any solution for this?
Yes, here people have faced the same issue. I will extend the answer.
You probably need to copy that video into the temporary folder, so in your UIImagePickerControllerDelegate's method:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String,
mediaType == "public.movie",
let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
// 1
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
// 2
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
// 3
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
// 4
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
// use the video file via targetFileURL path
}
}
}
Here you have trimVideURL, that needs to be sliced by .
file:///private/var/mobile/Containers/Data/PluginKitPlugin/ECD6D7FD-35A8-47E2-8323-808454A32C37/tmp/trim.919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
Create temporary directory:
file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/
Compose the target filename in temporary folder: file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
And finally copy item to your temporary folder using FileManager
And when you ready, you could delete the file using:
do {
try FileManager.default.removeItem(at: targetFileURL)
} catch {
print(error.localizedDescription)
}
Good article about temporary files
Also, you could use this test project as a reference, just copy it into new created project to test out functionality:
import UIKit
import WebKit
class ViewController: UIViewController, UINavigationControllerDelegate {
var imageView: UIImageView!
var videoView: WKWebView!
var selectButton: UIButton!
var deleteButton: UIButton!
var pickerController: UIImagePickerController?
var targetFileURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
setupPickerController()
}
func configureUI() {
imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
videoView = WKWebView()
videoView.translatesAutoresizingMaskIntoConstraints = false
selectButton = UIButton(type: .system)
selectButton.setTitle("Select", for: .normal)
selectButton.addTarget(self, action: #selector(showImagePicker), for: .touchUpInside)
selectButton.translatesAutoresizingMaskIntoConstraints = false
deleteButton = UIButton(type: .system)
deleteButton.setTitle("Delete", for: .normal)
deleteButton.addTarget(self, action: #selector(deleteCurrentTempFile), for: .touchUpInside)
deleteButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
view.addSubview(videoView)
view.addSubview(selectButton)
view.addSubview(deleteButton)
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true
videoView.topAnchor.constraint(equalTo: imageView.bottomAnchor).isActive = true
videoView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
videoView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
videoView.heightAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
deleteButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
deleteButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
deleteButton.heightAnchor.constraint(equalToConstant: 60.0).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
selectButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
selectButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
selectButton.heightAnchor.constraint(equalTo: deleteButton.heightAnchor).isActive = true
selectButton.bottomAnchor.constraint(equalTo: deleteButton.topAnchor).isActive = true
view.layoutIfNeeded()
}
func setupPickerController() {
self.pickerController = UIImagePickerController()
self.pickerController?.delegate = self
if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
self.pickerController?.mediaTypes = mediaTypes
}
}
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { [unowned self] _ in
self.pickerController?.sourceType = type
if let pickerController = self.pickerController {
self.present(pickerController, animated: true)
}
}
}
#IBAction func showImagePicker() {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .photoLibrary, title: "Photo library") {
alertController.addAction(action)
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true)
}
#IBAction func deleteCurrentTempFile() {
if let url = targetFileURL,
FileManager.default.fileExists(atPath: url.path) {
removeTemporaryFile(at: url)
}
}
func didSelectMedia(image: UIImage?, videoURL: URL?) {
if let image = image {
imageView.image = image
} else if let videoURL = videoURL {
let request = URLRequest(url: videoURL)
videoView.load(request)
targetFileURL = videoURL
}
}
// remove it when you done
func removeTemporaryFile(at url: URL) {
do {
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
targetFileURL = nil
}
}
extension ViewController: UIImagePickerControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String {
if mediaType == "public.movie", let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
self.didSelectMedia(image: nil, videoURL: targetFileURL)
} else {
self.didSelectMedia(image: nil, videoURL: trimVideoURL)
}
} else if mediaType == "public.image", let image = info[.originalImage] as? UIImage {
self.didSelectMedia(image: image, videoURL: nil)
}
}
picker.dismiss(animated: true, completion: nil)
}
}
maybe you should rename your file for now.
var lastPathComponent = yourFileURL.lastPathComponent
if lastPathComponent.lowercased().contains("trim") {
lastPathComponent = lastPathComponent.replacingOccurrences(of: "trim.", with: "")
try? yourFileURL.setResourceValue(lastPathComponent, forKey: URLResourceKey.nameKey)
// considering your fileURL is an nsurl
}
Related
initial view of view control where we start the download Once the download started it look like this I were working in a mp3 application where I need to download the mp3 from the list shown when the user click the download button it shows the control for pause, stop and a progress view. my download is working but I could not show the progress for the download all over the application. For example: if I am downloading some "x.mp3" song if the user click x.mp3 in VC1 the progress should also shown in VC3. Then the big problem I am facing is after downloading the download control should hide. Due to tableview reload function I cannot handle the UIrefresh which should show the download control and also the download button accordingly.
I have attached both my ViewController class the cell class and also the design
I have attached the "CELLFORROWATINDEXPATH" function for your reference and I have enclosed all the download functionality in the cell class.
viewcontroller Cellforrowatindexpath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let table_cell = tableView.dequeueReusableCell(withIdentifier: "LecturesVcCellID", for: indexPath) as! LecturesVcCell
let trackdata = searchResults[indexPath.row]
constantsList.playTypeArray.boolArray.append(false)
table_cell.configure(track: trackdata, index: indexPath.row)
table_cell.downloadbtn.tag = indexPath.row
table_cell.pauseButton.tag = indexPath.row
table_cell.cancelButton.tag = indexPath.row
table_cell.progressLabel.tag = indexPath.row
let x : Int = trackdata.classNumber as! Int
let className = String(x)
if index == indexPath.row {
table_cell.img_play.image=#imageLiteral(resourceName: "playing_track")
table_cell.lbl_SubTitle.text = "Now playing"
table_cell.lbl_SubTitle.textColor = #colorLiteral(red: 0.968627451, green: 0.7490196078, blue: 0.4823529412, alpha: 1)
}else {
table_cell.img_play.image=#imageLiteral(resourceName: "play_track")
table_cell.lbl_SubTitle.text = String(format: "Class - %# | %#", className,(trackdata.timeoftrack!))
table_cell.lbl_SubTitle.textColor = UIColor.lightGray
}
str_image = "https://www.imaginetventures.name/swamiji/wp-content/uploads/2019/01/introved.png"
constantsList.playTypeArray.imageLecture = str_image
table_cell.img_Show.sd_setImage(with: URL(string: str_image), placeholderImage: UIImage(named: "placeholder.png"))
table_cell.navigationController = self.navigationController
if str_Type .isEqual(to: "Playlist") {
table_cell.downloadbtn.isHidden = true
// table_cell.playlistAdditionImageview.isHidden = false
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
table_cell.playlistAdditionImageview.isHidden = true
}else {
table_cell.playlistAdditionImageview.isHidden = false
}
}else {
table_cell.downloadbtn.setImage(UIImage(named: "DATA11"), for: .normal)
// table_cell.playlistAdditionImageview.isHidden = true
}
table_cell.selectionStyle = .none
return table_cell
}
viewcontrollercell classfile:
override func awakeFromNib() {
super.awakeFromNib()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
context = appDelegate.persistentContainer.viewContext
entity = NSEntityDescription.entity(forEntityName: "DownloadList", in: context)
}
#IBAction func pauseBtnAction (_ sender: UIButton) {
if(downloadTask != nil && isDownload) {
downloadTask!.cancel(byProducingResumeData: { (resumeData) -> Void in
self.downloadData = resumeData
})
isDownload = false
downloadTask = nil
pauseButton.setImage(UIImage(named: "start-button"), for: .normal)
}else
if(!isDownload && downloadData != nil) {
if let resumeData = self.downloadData {
downloadTask = urlSession?.downloadTask(withResumeData: resumeData)
} else {
let url:URL = URL(string: "\((constantsList.playTypeArray.arr_subCatagriesLecture.object(at: sender.tag) as AnyObject).value(forKey: "mp3") as! String)")!
downloadTask = downloadsSession?.downloadTask(with: url)
}
downloadTask!.resume()
isDownload = true
pauseButton.setImage(UIImage(named: "x"), for: .normal)
}
}
#IBAction func cancelBtnClicked (_ sender: UIButton) {
downloadTask?.cancel()
downloadData = nil
isDownload = false
downloadTask = nil
progress.progress = 0
progressLabel.text = "0%"
progress.setProgress(0.0, animated: true)
cancelButton.isHidden = true
pauseButton.isHidden = true
downloadbtn.isHidden = false
progressLabel.isHidden = true
progress.isHidden = true
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let completionHandler = appDelegate.backgroundSessionCompletionHandler {
appDelegate.backgroundSessionCompletionHandler = nil
completionHandler()
}
}
}
#IBAction func downloadBtnAction(_ sender: UIButton) {
// sender.pulse()
self.reachability = Reachability.init()
if ((self.reachability?.connection) != .none) {
switch self.reachability?.connection {
case .wifi?:
print("Wifi")
print(sender.tag)
constantsList.playTypeArray.typeofnetwork = true
downloadTapped(sender: sender.tag)
case .cellular?:
print("mobile data")
print(sender.tag)
let alert = UIAlertController(title: "Mobile Data usage Alert!", message: "Downloads will be using mobile data!!", preferredStyle: UIAlertController.Style.alert);
let action1 = UIAlertAction(title: "Ok", style: .default) { (action:UIAlertAction) in
self.downloadTapped(sender: sender.tag)
}
let action2 = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
print("Cancelled")
}
alert.addAction(action1)
alert.addAction(action2)
self.navigationController?.present(alert, animated: true, completion: nil)
case .none:
print("Network Not reachable")
case .some(.none):
print("Some")
}
}else {
print("No Internet")
}
}
func downloadTapped(sender : Int) {
constantsList.playTypeArray.arrayDownloadSort.append(sender as NSNumber)
print(constantsList.playTypeArray.arrayDownloadSort)
constantsList.playTypeArray.boolArray[sender] = true
showDownloadControls = true
downloadbtn.isHidden = true
pauseButton.isHidden = false
cancelButton.isHidden = false
progressLabel.isHidden = true
progress.isHidden = false
progressLabel.text = "Downloading..."
var urlConfiguration:URLSessionConfiguration!
urlConfiguration = URLSessionConfiguration.default
let queue:OperationQueue = OperationQueue.main
urlSession = URLSession.init(configuration: urlConfiguration, delegate: self, delegateQueue: queue)
let url:NSURL = NSURL(string: "\((constantsList.playTypeArray.arr_subCatagriesLecture.object(at: sender) as AnyObject).value(forKey: "mp3") as! String)")!
downloadTask = urlSession.downloadTask(with: url as URL)
downloadTask.resume()
}
//DOWNLOADING THE FILE UPDATE THE PROGRESS
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// 2
let progress1 = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite);
// 3
print(progress1)
// 4
// OperationQueue.main.addOperation
DispatchQueue.main.async (execute: {
self.isDownload = true
// 2
constantsList.playTypeArray.isDownloading = true
self.progress.setProgress(progress1, animated: false)
self.progressLabel.text = String(progress1 * 100) + "%"
constantsList.playTypeArray.setprogress = progress1
let i = 0
if progress1 == 1.0 {
constantsList.playTypeArray.isDownloading = false
print(i + 1)
}
})
}
//AFTER DOWNLOADING SAVE THE FILE TO APP DATA
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("Finish Downloading")
let filemanager = FileManager()
let directoryURL = filemanager.urls(for: .documentDirectory, in: .userDomainMask)[0]
print(directoryURL)
let docDirectoryURL = NSURL(fileURLWithPath: "\(directoryURL)")
print(docDirectoryURL)
let destinationFileName = downloadTask.originalRequest?.url?.lastPathComponent
print(destinationFileName!)
let destinationURL = docDirectoryURL.appendingPathComponent("\(destinationFileName!)")
print(destinationURL!)
if let path = destinationURL?.path {
if filemanager.fileExists(atPath: path) {
do {
try filemanager.removeItem(at: destinationURL!)
}catch let error as NSError{
print(error.localizedDescription)
}
}
}
do {
try filemanager.copyItem(at: location, to: destinationURL!)
print(destinationURL!)
print(downloadbtn.tag)
newUser = NSManagedObject(entity: entity!, insertInto: context)
dic66 = constantsList.playTypeArray.arr_subCatagriesLecture.object(at: downloadbtn.tag) as? NSDictionary
newUser.setValue(dic66?.value(forKey: "classname") as! NSNumber, forKey: "classname")
newUser.setValue("\(String(describing: dic66?.value(forKey: "time") as! String))", forKey: "time")
newUser.setValue("\(String(describing: dic66?.value(forKey: "title") as! String))", forKey: "songtitle")
newUser.setValue("\(destinationURL!.path)", forKey: "mp3Url")
newUser.setValue("\(String(describing: constantsList.playTypeArray.imageLecture!))", forKey: "imageurl")
do {
try context.save()
print(context)
self.cancelButton.isHidden = true
self.pauseButton.isHidden = true
self.downloadbtn.isHidden = true
self.progressLabel.isHidden = true
self.progress.isHidden = true
print("Successful")
} catch {
print("failed")
}
}catch {
print("Error while copying file")
}
downloadData = nil;
}
func configure(track: Track,index: Int) {
var filefound: Bool = false
var shopwControls: Bool = true
if(constantsList.playTypeArray.boolArray[index]) {
filefound = true
shopwControls = false
self.progress.setProgress(constantsList.playTypeArray.setprogress, animated: true)
}
lbl_Title.text = track.songTitle
//CLASS AND VOLUME UPDATION
let x : Int = track.classNumber as! Int
let className = String(x)
lbl_SubTitle.text = String(format: "Class - %# | %#", className,(track.timeoftrack!))
//core Data checking for already downloaded file
request.returnsObjectsAsFaults = false
request.resultType = .dictionaryResultType
do {
let result = try context.fetch(request)
dic66 = constantsList.playTypeArray.arr_subCatagriesLecture.object(at: index) as? NSDictionary
for data in result as! [[String:Any]] {
print(data["classname"] as! Int)
print(dic66?.value(forKey: "classname") as! Int)
if data["classname"] as! Int == (dic66?.value(forKey: "classname") as! Int) {
filefound = true
}
}
} catch {
print("Failed")
}
// If the track is already downloaded, enable cell selection and hide the Download button
selectionStyle = filefound ? UITableViewCell.SelectionStyle.gray : UITableViewCell.SelectionStyle.none
downloadbtn.isHidden = filefound
pauseButton.isHidden = shopwControls
cancelButton.isHidden = shopwControls
progress.isHidden = shopwControls
}
}
I am currently loading images from my server. The images are plenty depending on the number of images it return. I have been able to display these images successfully and I can scroll down to view all images. Now my problem is I want a way which I can click on a specific image i will be able to zoom it. I have shared my code below:
//Declaration of variables
var albumID: String?
var imagePath: String?
var path: String?
var getClickImage = UIImageView()
var zoomscrollV = UIScrollView()
var imageArray = [String]()
//view did load
override func viewDidLoad() {
super.viewDidLoad()
setUpViewsAlbumPhotos()
zoomscrollV.delegate = self
if !CheckInternet.Connection(){
showAlert(title: "No Internet", message: "Please connect your device to an internet connection")
}else{
fetchPhotos(albumID: albumID)
}
}
//viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
zoomscrollV.isHidden = true
zoomscrollV.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height - 50)
zoomscrollV.minimumZoomScale=1
zoomscrollV.maximumZoomScale=10
zoomscrollV.bounces=false
self.view.addSubview(zoomscrollV)
getClickImage=UIImageView()
getClickImage.frame = CGRect(x:0, y:0, width:zoomscrollV.frame.width, height:zoomscrollV.frame.height)
getClickImage.backgroundColor = .black
getClickImage.contentMode = .scaleAspectFit
zoomscrollV.addSubview(getClickImage)
}
//This code makes an async call to download images and details from the server
let async_call = URL(string: "\(String.api_albumPhotos)\(albumID ?? "")")
let request = NSMutableURLRequest(url: async_call!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil {
print("error is:: \(error!.localizedDescription)")
DispatchQueue.main.async {
self.showAlert(title: "Error", message: "Sorry try again later")
self.stopActivityLoader()
}
return
}
do {
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = myJSON {
var responseCode: String!
var message: NSArray!
responseCode = parseJSON["responseCode"] as! String?
if responseCode == "200" {
DispatchQueue.main.async {
self.stopActivityLoader()
message = parseJSON["message"] as? NSArray
self.path = parseJSON["path"] as? String
if let message = message {
let totalMessage = message.count
let viewHeight = self.view.frame.height
var scrollHeight = 0
var contentViewTopConstraint: CGFloat = 20
// self.preference.set(parseJSON, forKey: UserDefaultKeys.albums.rawValue)
for obj in message{
if let dict = obj as? NSDictionary {
self.imagePath = dict.value(forKey: "path") as? String
let imageID = dict.value(forKey: "id") as? String
let albumThumbnail = photos()
self.scrollView.addSubview(albumThumbnail)
albumThumbnail.translatesAutoresizingMaskIntoConstraints = false
albumThumbnail.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor).isActive = true
albumThumbnail.topAnchor.constraint(equalTo: self.scrollView.topAnchor, constant: contentViewTopConstraint).isActive = true
albumThumbnail.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor).isActive = true
albumThumbnail.heightAnchor.constraint(equalToConstant: 150).isActive = true
albumThumbnail.isUserInteractionEnabled = true
albumThumbnail.contentMode = .scaleAspectFit
let touchRec = UITapGestureRecognizer(target: self, action: #selector(self.myImageTapped(_:)))
albumThumbnail.addGestureRecognizer(touchRec)
if let path = self.path{
if let imagePath = self.imagePath{
let strippedPath = path.replacingOccurrences(of: "\\", with: "")
let strippedImagePath = imagePath.replacingOccurrences(of: "\\", with: "")
print("\(strippedPath)\(strippedImagePath)")
albumThumbnail.sd_setImage(with: URL(string: "\(strippedPath)\(strippedImagePath)"), placeholderImage: UIImage(named: "default_profile"), options: [.continueInBackground, .progressiveDownload])
if let wrapped = self.path {
self.imageArray.append("\(strippedPath)\(strippedImagePath)")
// print(self.imageArray.append(wrapped))
}
}
}
contentViewTopConstraint = contentViewTopConstraint + 170
}
}
scrollHeight = totalMessage * 170
if totalMessage <= 1 {
self.scrollView.contentSize.height = viewHeight + 20
}else{
self.scrollView.contentSize.height = CGFloat(scrollHeight)
}
}
}
}else{
//Show alert
DispatchQueue.main.async {
self.showAlert(title: "Error", message: "Sorry could not update album. Try again")
self.stopActivityLoader()
}
}
}
}catch{
print("you:: \(error.localizedDescription)")
//Show alert
DispatchQueue.main.async {
self.showAlert(title: "Error", message: "Sorry could not update album. Try again")
self.stopActivityLoader()
}
}
}
task.resume()
}
#objc func myImageTapped(_ sender: UITapGestureRecognizer) {
zoomscrollV.isHidden = false
let myImage = imageArray[(sender.view?.tag)!]
print("myImage \(myImage)")
// RESPECTIVE IMAGE
getClickImage.image = UIImage(named: myImage)
let closeButton: UIButton = UIButton(type: .custom)
closeButton.frame = CGRect(x:40.0, y:self.view.frame.height - 50, width:self.view.frame.width - 80, height:50.0)
closeButton.addTarget(self, action: #selector(self.closeZoom), for: .touchUpInside)
closeButton.setTitle("CLOSE ZOOM", for: .normal)
closeButton.setTitleColor(UIColor.white, for: .normal)
// CLOSE BUTTON
self.view.addSubview(closeButton)
}``
#objc func closeZoom(sender: AnyObject) {
zoomscrollV.isHidden = true
zoomscrollV.setZoomScale(1.0, animated: false)
sender.removeFromSuperview()
}
//SCROLLVIEW DELEGATE
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return getClickImage
}
========================== Edit Jan 24 ============================
CONVERT URL TO IMAGE
#objc func myImageTapped(_ sender: UITapGestureRecognizer) {
zoomscrollV.isHidden = false
let myImageURL = imageArray[(sender.view?.tag)!]
if let url = URL( string: myImageURL)
{
DispatchQueue.global().async {
if let data = try? Data( contentsOf:url){
DispatchQueue.main.async {
let myImage = UIImage( data:data)
print("myImage \(myImage)")
// RESPECTIVE IMAGE
getClickImage.image = UIImage(named: myImage)
let closeButton: UIButton = UIButton(type: .custom)
closeButton.frame = CGRect(x:40.0, y:self.view.frame.height - 50, width:self.view.frame.width - 80, height:50.0)
closeButton.addTarget(self, action: #selector(self.closeZoom), for: .touchUpInside)
closeButton.setTitle("CLOSE ZOOM", for: .normal)
closeButton.setTitleColor(UIColor.white, for: .normal)
// CLOSE BUTTON
self.view.addSubview(closeButton)
}
}
}
}
===============================================================
On image click, U have create scrollview and add respective image as subview, then zoom will work out.
var getClickImage = UIImageView()
var zoomscrollV = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
zoomscrollV.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
zoomscrollV.isHidden = true
zoomscrollV.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height - 50)
zoomscrollV.minimumZoomScale=1
zoomscrollV.maximumZoomScale=10
zoomscrollV.bounces=false
self.view.addSubview(zoomscrollV)
getClickImage=UIImageView()
getClickImage.frame = CGRect(x:0, y:0, width:zoomscrollV.frame.width, height:zoomscrollV.frame.height)
getClickImage.backgroundColor = .black
getClickImage.contentMode = .scaleAspectFit
zoomscrollV.addSubview(getClickImage)
}
// ON CLICKING IMAGE ACTION
#objc func myImageTapped(_ sender: UITapGestureRecognizer) {
zoomscrollV.isHidden = false
// RESPECTIVE IMAGE
getClickImage.image = BG_CARD_IMGS[(sender.view?.tag)!]
let closeButton: UIButton = UIButton(type: .custom)
closeButton.frame = CGRect(x:40.0, y:self.view.frame.height - 50, width:self.view.frame.width - 80, height:50.0)
closeButton.addTarget(self, action: #selector(self.closeZoom), for: .touchUpInside)
closeButton.setTitle("CLOSE ZOOM", for: .normal)
closeButton.setTitleColor(UIColor.red, for: .normal)
// CLOSE BUTTON
self.view.addSubview(closeButton)
}
#objc func closeZoom(sender: AnyObject) {
zoomscrollV.isHidden = true
zoomscrollV.setZoomScale(1.0, animated: false)
sender.removeFromSuperview()
}
//SCROLLVIEW DELEGATE
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return getClickImage
}
OUTPUT
I'm trying to download a photo user account from Firebase.
I explain my issue:
On the profil page of the user, there's a button showing his current image for his profil avatar, first there's no image in the button background, when he clicks the first time he could choose an image in his photo library or take a photo by the device camera (by alert controller), then this image or photo is uploaded in Firebase Storage, and the new photo is showing on the button background.
But when the user wants to change his current photo, he tap the button again and choose or take a photo, but after he did that, the button background doesn't change, it means user changes his photo but on the current page the photo doesn't update the changes, but if I go another view and come back on the change photo view, the right photo of the user just chooses are in the button background. So the download can works good but not immediately if users didn't go another view. It a little difficult to explain.
Here's my code for my upload way :
// Variables I need
#IBOutlet weak var photoProfil: UIButton!
var name: String!
var userUid: String!
#IBOutlet var userImagePicker: UIImageView!
var imagePicker: UIImagePickerController!
var imageSelected = false
var isUploaded: Bool = false
var refDatabase: DatabaseReference!
var photovide: UIImage = UIImage(named:"profilvide")!
// Take a photo with the camera (first choice)
func takePhoto(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.camera // Source Camera
self.present(imagePicker, animated: false, completion: nil)
} else { // If camera doesn't work
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary // Source Library
self.present(imagePicker, animated: false, completion: nil)
}
}
// Choose an image from the library
func libraryPhoto(sender: AnyObject) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
}
// Take this image and shows it on the View Controller
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
// I want to upload the photo to storage and save it in the database
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
photoProfil.setImage(image, for: .normal) // Button showing the user photo
userImagePicker.image = image
imageSelected = true
uploadImg()
} else {
print("Error...")
}
imagePicker.dismiss(animated: true, completion: nil)
self.dismiss(animated: true, completion: nil)
}
// The alert Controller
#IBAction func actionButton(_ sender: Any) {
let attributedString = NSAttributedString(string: "User photo", attributes: [
NSFontAttributeName : UIFont.boldSystemFont(ofSize: 15),
NSForegroundColorAttributeName : UIColor.black
])
let alertController = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alertController.message = nil
alertController.setValue(attributedString, forKey: "attributedTitle")
alertController.addAction(UIAlertAction(title: "Take photo", style: .default, handler: self.takePhoto))
alertController.addAction(UIAlertAction(title: "Choose in Library", style: .default, handler: self.libraryPhoto))
alertController.addAction(UIAlertAction(title: "Show current photo", style: .default, handler: self.showPhoto))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
// Create a path in order to save the photo in Firebase
func setUser(img: String) {
var userUid = Auth.auth().currentUser?.uid
let userData = [
"nickname": Auth.auth().currentUser?.displayName,
"userImg": img
]
KeychainWrapper.standard.set(userUid!, forKey: "uid")
let location = Database.database().reference().child("users").child(userUid!).child("pseudo")
location.setValue(userData)
dismiss(animated: true, completion: nil)
}
// Upload and put image in the Firebase Storage
func uploadImg() {
guard let img = userImagePicker.image, imageSelected == true else {
print("Image needs to be selected")
return
}
if let imgData = UIImageJPEGRepresentation(img, 0.2) {
let imgUid = NSUUID().uuidString
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
Storage.storage().reference().child(imgUid).putData(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("Did not upload img")
self.isUploaded = false
} else {
print("uploaded")
self.isUploaded = true
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
self.setUser(img: url)
}
}
}
}
}
Here's the code for the download way and show photo after downloaded :
override func viewDidLoad() {
super.viewDidLoad()
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
// For download photo from Firebase
name = Auth.auth().currentUser?.displayName
userUid = Auth.auth().currentUser?.uid
refDatabase = Database.database().reference().child("users").child(userUid!)
refDatabase.child("pseudo").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild("userImg") {
self.isUploaded = true
print("True userImg exists")
self.downloadPhoto(user: self.name)
} else {
self.isUploaded = false
self.userImagePicker = UIImageView(image: self.photovide)
self.photoProfil.setImage(self.photovide, for: .normal)
print("isUploaded2 = false")
print("false userImg doesn't exist")
print("Aucune photo n'a été uploadée dans la base de données")
}
})
}
override func viewWillAppear(_ animated: Bool) {
self.userImagePicker.image = nil
guard let username = Auth.auth().currentUser?.displayName else { return }
self.navigationItem.title = username
refDatabase = Database.database().reference().child("users").child(userUid!)
refDatabase.child("pseudo").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild("userImg") {
self.isUploaded = true
print("isUploaded2 = true")
print("true userImg exists")
self.downloadPhoto(user: self.name)
} else {
self.isUploaded = false
self.userImagePicker = UIImageView(image: self.photovide)
self.photoProfil.setImage(self.photovide, for: .normal)
print("False userImg doesn't exist")
}
})
}
func downloadPhoto(user: String) {
self.name = user
let recipientData = Database.database().reference().child("users").child(userUid!).child("pseudo")
recipientData.observeSingleEvent(of: .value, with: { (snapshot) in
let data = snapshot.value as! Dictionary<String, AnyObject>
let nickname = data["nickname"]
let userImg = data["userImg"]
let ref = Storage.storage().reference(forURL: userImg! as! String)
ref.getData(maxSize: 1000000, completion: { (data, error) in
if error != nil {
print("Could not load image")
} else {
if let imgData = data {
if let img = UIImage(data: imgData) {
self.userImagePicker.image = img
self.photoProfil.setImage(img, for: .normal)
}
}
}
})
})
userImagePicker.reloadInputViews()
}
func dismissFullscreenImage(_ sender: UITapGestureRecognizer) {
self.navigationController?.isNavigationBarHidden = false
self.tabBarController?.tabBar.isHidden = false
sender.view?.removeFromSuperview()
}
// Try to do the same with the viewDidLoad() method for download but can't work
override func viewDidAppear(_ animated: Bool) {
refDatabase = Database.database().reference().child("users").child(userUid!)
refDatabase.child("pseudo").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild("userImg") {
self.isUploaded = true
print("True userImg exists")
self.downloadPhoto(user: self.name)
} else {
self.isUploaded = false
self.userImagePicker = UIImageView(image: self.photovide)
self.photoProfil.setImage(self.photovide, for: .normal)
print("False userImg doesn't exist")
}
})
}
You should try to call the downloadPhoto() method in the uploadImg() method.
Like this :
func uploadImg() {
name = Auth.auth().currentUser?.displayName
userUid = Auth.auth().currentUser?.uid
guard let img = userImagePicker.image, imageSelected == true else {
print("Image needs to be selected")
return
}
if let imgData = UIImageJPEGRepresentation(img, 0.2) {
let imgUid = NSUUID().uuidString
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
Storage.storage().reference().child(imgUid).putData(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("Did not upload img")
self.isUploaded = false
} else {
print("Uploaded")
self.isUploaded = true
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
self.setUser(img: url)
self.downloadPhoto(user: self.name) // Here add it
}
}
}
}
}
You could too make a function with a piece of code you use in viewDidLoad() and in viewWillAppear() and call this function in this 2 methods for proper code.
Hope it helps.
I have a tableview and have multiple cells in tableView.
Each cell has an item of AVAudioPlayer
And I face a problem.
I don't know how to manage the AVAudioPlayer.
When I play first AVAudioPlayer, and then play second AVAudioPlayer, the sound will overlap.
How to stop first AVAudioPlayer in my customized cell, and play second AVAudioPlayer?
Thanks.
This is my customized cell:
class TableViewCell: UITableViewCell {
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var myChatBubbleView: UIView!
#IBOutlet weak var myDateLabel: UILabel!
#IBOutlet weak var mySecondLabel: UILabel!
#IBOutlet weak var myRecordPlayerBtn: MenuButton!
private var timer:Timer?
private var elapsedTimeInSecond:Int = 0
var audioPlayer:AVAudioPlayer?
var message:ChatroomMessage?
var chatroomId:String = ""
var delegate:PlayRecordDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = defaultBackgroundColor
self.tintColor = defaultChatroomCheckButtonColor
myImageView.layer.masksToBounds = true
myImageView.layer.cornerRadius = defaultIconRadius
myChatBubbleView.backgroundColor = defaultChatGreenBubbleColor
myChatBubbleView.layer.cornerRadius = defaultButtonRadius
myDateLabel.textColor = defaultChatTimeColor
mySecondLabel.textColor = defaultChatTimeColor
mySecondLabel.isHidden = true
myRecordPlayerBtn.imageView?.animationDuration = 1
myRecordPlayerBtn.imageView?.animationImages = [
UIImage(named: "img_myRocordPlaying1")!,
UIImage(named: "img_myRocordPlaying2")!,
UIImage(named: "img_myRocordPlaying3")!
]
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func loadByMessage(_ message:ChatroomMessage, chatroomId:String) {
self.message = message
self.chatroomId = chatroomId
myRecordPlayerBtn.addTarget(self, action: #selector(recordPlay), for: .touchUpInside)
}
func resetRecordAnimation() {
self.myRecordPlayerBtn.imageView!.stopAnimating()
self.myRecordPlayerBtn.isSelected = false
}
func recordPlay(_ sender: UIButton) {
self.myRecordPlayerBtn.imageView?.startAnimating()
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(chatroomId)/Record/")
let fileName = message?.content.substring(from: 62)
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)
if FileManager.default.fileExists(atPath: fileURL.path) {
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
self.elapsedTimeInSecond = Int(audioDurationSeconds)
if audioPlayer?.isPlaying == true {
audioPlayer?.stop()
DispatchQueue.main.async {
self.resetTimer(second: self.elapsedTimeInSecond)
self.startTimer()
}
}
updateTimeLabel()
startTimer()
audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
audioPlayer?.delegate = self
audioPlayer?.play()
}else{
//don't have file in local
let recordUrl = URL(string: (message?.content)!)
URLSession.shared.downloadTask(with: recordUrl!, completionHandler: { (location, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
let location = location, error == nil
else { return }
do {
try FileManager.default.moveItem(at: location, to: fileURL)
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
self.elapsedTimeInSecond = Int(audioDurationSeconds)
DispatchQueue.main.async {
self.updateTimeLabel()
self.startTimer()
}
self.audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
self.audioPlayer?.delegate = self
self.audioPlayer?.play()
} catch {
print(error)
}
}).resume()
}
}
func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { (timer) in
self.elapsedTimeInSecond -= 1
self.updateTimeLabel()
})
}
func resetTimer(second:Int) {
timer?.invalidate()
elapsedTimeInSecond = second
updateTimeLabel()
}
func updateTimeLabel() {
let seconds = elapsedTimeInSecond % 60
let minutes = (elapsedTimeInSecond/60) % 60
mySecondLabel.isHidden = false
mySecondLabel.text = String(format: "%02d:%02d", minutes,seconds)
}
}
extension TableViewCell:AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Id)/Record/")
let fileName = message?.content.substring(from: 62)
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)
if FileManager.default.fileExists(atPath: fileURL.path) {
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
DispatchQueue.main.async {
self.resetTimer(second: Int(audioDurationSeconds))
self.myRecordPlayerBtn.imageView!.stopAnimating()
self.myRecordPlayerBtn.imageView?.image = #imageLiteral(resourceName: "img_myRocordDefault")
}
}
}
}
Probably first initialize to check if your player is playing
if audioPlayer != nil{
if audioPlayer?.isPlaying == true {
audioPlayer?.stop()
DispatchQueue.main.async {
self.resetTimer(second: self.elapsedTimeInSecond)
self.startTimer()
}
}
}
If you don't want to play two audio track at the same time, you should use a shared instance of AVAudioPlayer
It will be better for performances and you can define the instance as static var in your controller. It will be accessible in each cell.
I have developed a music palyer application, and I used a shared instance in the MusicPlayManager:
class MusicPlayManager{
var player : AVAudioPlayer?
static let sharedInstance = MusicPlayManager.init()
private override init() {
super.init()
}
// something else, such as palyNext, playPrevious methods
}
In your viewController,you can use MusicPlayManager.sharedInstance.player
Sorry for the question without a code.But i didn't find anywhere to look for.
I want to share image with title in instagram? How can i do that?
Any help would be great
if you don't want to use UIDocumentInteractionController
SWIFT 5 update
import Photos
...
func postImageToInstagram(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if error != nil {
print(error)
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
if let lastAsset = fetchResult.firstObject as? PHAsset {
let url = URL(string: "instagram://library?LocalIdentifier=\(lastAsset.localIdentifier)")!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else {
let alertController = UIAlertController(title: "Error", message: "Instagram is not installed", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
}
Swift 3.0 Version :
#IBAction func shareInstagram(_ sender: Any) {
DispatchQueue.main.async {
//Share To Instagram:
let instagramURL = URL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramURL!) {
let imageData = UIImageJPEGRepresentation(image, 100)
let writePath = (NSTemporaryDirectory() as NSString).appendingPathComponent("instagram.igo")
do {
try imageData?.write(to: URL(fileURLWithPath: writePath), options: .atomic)
} catch {
print(error)
}
let fileURL = URL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(url: fileURL)
self.documentController.delegate = self
self.documentController.uti = "com.instagram.exlusivegram"
if UIDevice.current.userInterfaceIdiom == .phone {
self.documentController.presentOpenInMenu(from: self.view.bounds, in: self.view, animated: true)
} else {
self.documentController.presentOpenInMenu(from: self.IGBarButton, animated: true)
}
} else {
print(" Instagram is not installed ")
}
}
}
class viewController: UIViewController, UIDocumentInteractionControllerDelegate {
var yourImage: UIImage?
var documentController: UIDocumentInteractionController!
func shareToInstagram() {
let instagramURL = NSURL(string: "instagram://app")
if (UIApplication.sharedApplication().canOpenURL(instagramURL!)) {
let imageData = UIImageJPEGRepresentation(yourImage!, 100)
let captionString = "caption"
let writePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("instagram.igo")
if imageData?.writeToFile(writePath, atomically: true) == false {
return
} else {
let fileURL = NSURL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(URL: fileURL)
self.documentController.delegate = self
self.documentController.UTI = "com.instagram.exlusivegram"
self.documentController.annotation = NSDictionary(object: captionString, forKey: "InstagramCaption")
self.documentController.presentOpenInMenuFromRect(self.view.frame, inView: self.view, animated: true)
}
} else {
print(" Instagram isn't installed ")
}
}
}
Now this still wont work with iOS 9, so you will have to go to your apps info.plist, add "LSApplicationQueriesSchemes" type: Array, and add the URL Scheme in this case "instagram".
Here try this code
#IBAction func shareContent(sender: UIButton) {
let image = UIImage(named: "imageName")
let objectsToShare: [AnyObject] = [image!]
let activityViewController = UIActivityViewController(
activityItems: objectsToShare,
applicationActivities: nil
)
activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.excludedActivityTypes = [
UIActivityTypeAirDrop,
UIActivityTypePostToFacebook
]
self.presentViewController(
activityViewController,
animated: true,
completion: nil
)
}