When I set the externalMetadata on my AVPlayerItem and load it into the player of AVPlayerViewController it loads my metadata in the Info but the text is faded http://drop.lyokotech.com/image/0F0V2W1c431A/Screen%20Shot%202015-11-10%20at%2014.30.03.png
Any idea why this would happen? This is how I am loading it (From the root view controller)
func getMetadata() -> [AVMetadataItem] {
var items = [AVMetadataItem]()
func createMetaDataItem(key: String, value: String) -> AVMetadataItem {
let data = AVMutableMetadataItem()
data.key = key
data.value = value
data.keySpace = AVMetadataKeySpaceCommon
data.locale = NSLocale.currentLocale()
return data
}
let title = createMetaDataItem(AVMetadataCommonKeyTitle, value: "SOME TITLE")
let description = createMetaDataItem(AVMetadataCommonKeyDescription, value: "SOME DESCRIPTION")
items.append(title)
items.append(description)
return items
}
let metadata = getMetadata()
if let path = NSBundle.mainBundle().pathForResource("IMG_0343", ofType: "MOV") {
let url = NSURL(fileURLWithPath: path)
let item = AVPlayerItem(URL: url)
item.externalMetadata = metadata
let player = AVPlayer(playerItem: item)
let av = AVPlayerViewController()
av.player = player
av.player?.play()
presentViewController(av, animated: true, completion: nil)
}
This happens whether I use a local file or a stream (HLS)
This is due to a problem in a simulator. It will work fine on a real device.
Related
I’m trying to display my JSON into my UIImageView and UILabel. I have the JSON in my console but it is not being presented onto the label or ImageView. I am not getting errors, but nothing is displayed using the following JSON.
override func viewDidLoad()
{
print(currentUser!)
super.viewDidLoad()
loadUser()
refreshControl?.tintColor = .black
self.tableView.addSubview(refreshControl!)
}
func loadUser()
{
// save method of accessing user related info in global var
guard let firstName = currentUser?["firstName"], let lastName = currentUser?["lastName"], let username = currentUser?["username"], let profileImage = currentUser?["profileImage"] else
//guard let firstName = currentUser?["firstName"], let lastName = currentUser?["lastName"], let username = currentUser?["username"], let profileImagePath = currentUser?["profileImage"] else
{
return
}
fullNameLabel.text = "\((firstName as! String).capitalized) \((lastName as! String).capitalized)" // "Bob Michael"
usernameLabel.text = "#\(username as! String)"
Helper().downloadImage(from: profileImage as! String, showIn: self.ProfileImageView, orShow: "")
}
// allows us to download the image from certain url string
func downloadImage(from path: String, showIn imageView: UIImageView, orShow placeholder: String) {
// if avaPath string is having a valid url, IT'S NOT EMPTY (e.g. if ava isn't assigned, than in DB the link is stored as blank string)
if String(describing: path).isEmpty == false {
DispatchQueue.main.async {
// converting url string to the valid URL
if let url = URL(string: path) {
// downloading all data from the URL
guard let data = try? Data(contentsOf: url) else {
imageView.image = UIImage(named: placeholder)
return
}
// converting donwloaded data to the image
guard let image = UIImage(data: data) else {
imageView.image = UIImage(named: placeholder)
return
}
// assigning image to the imageView
imageView.image = image
}
}
}
}
I have a problem in modifying the video format after downloading from videoplayback to mp4 and save to camera.
This is my download code, but I downloaded some video with a different format example : "videoplayback". I can't save to camera because I want to change format video to mp4.
func SessionDownload(URLSession : String) {
MBProgressHUD.hideAllHUDs(for: view, animated: true)
let hud = MBProgressHUD.showAdded(to: self.view, animated: true)
// Set the bar determinate mode to show task progress.
progress = 0.0
hud?.mode = MBProgressHUDMode.determinateHorizontalBar
hud?.isUserInteractionEnabled = true;
hud?.labelText = NSLocalizedString("Downloading...", comment: "HUD loading title")
DispatchQueue.global(qos: .default).async(execute: {() -> Void in
// Do something useful in the background and update the HUD periodically.
self.doSomeWorkWithProgress()
DispatchQueue.main.async(execute: {() -> Void in
//hud?.hide(true)
hud?.labelText = NSLocalizedString("Just Wait...", comment: "HUD loading title")
})
})
let videoPath = URLSession
print(videoPath)
let s = videoPath
let url = NSURL(string:s)!
let req = NSMutableURLRequest(url:url as URL)
let config = URLSessionConfiguration.default
let task = self.session.downloadTask(with: req as URLRequest)
self.task = task
task.resume()
}
//MARK:- share video
func doSomeWorkWithProgress() {
// This just increases the progress indicator in a loop.
while progress < 1.0 {
DispatchQueue.main.async(execute: {() -> Void in
print(self.progress)
MBProgressHUD(for: self.view).progress = self.progress
})
usleep(50000)
}
}
//MARK:- URL Session delegat
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
print("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
taskTotalBytesWritten = Int(totalBytesWritten)
taskTotalBytesExpectedToWrite = Int(totalBytesExpectedToWrite)
percentageWritten = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)
print(percentageWritten)
let x = String(format:"%.2f", percentageWritten)
print(x)
self.progress = Float(x)!
print(progress)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
// unused in this example
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("completed: error: \(error)")
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("Finished downloading!")
let fileManager = FileManager()
// this can be a class variable
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
print(directoryURL)
let docDirectoryURL = NSURL(fileURLWithPath: "\(directoryURL)")
print(docDirectoryURL)
//Save To Photos
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL:directoryURL)
}) { saved, error in
if saved {
let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
let destinationFilename = downloadTask.originalRequest?.url?.lastPathComponent
print(destinationFilename!)
// append that to your base directory
let destinationURL = docDirectoryURL.appendingPathComponent("\(destinationFilename!)")
print(destinationURL!)
/* check if the file exists, if so remove it. */
if let path = destinationURL?.path {
if fileManager.fileExists(atPath: path) {
do {
try fileManager.removeItem(at: destinationURL!)
} catch let error as NSError {
print(error.debugDescription)
}
}
}
do
{
try fileManager.copyItem(at: location, to: destinationURL!)
}
catch {
print("Error while copy file")
}
DispatchQueue.main.async(execute: {() -> Void in
MBProgressHUD.hide(for: self.view, animated: true)
})
// let videoLink = NSURL(fileURLWithPath: filePath)
let objectsToShare = [destinationURL!] //comment!, imageData!, myWebsite!]
let activityVC = UIActivityViewController(activityItems: objectsToShare , applicationActivities: nil)
activityVC.setValue("Video", forKey: "subject")
//New Excluded Activities Code
if #available(iOS 9.0, *) {
activityVC.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact, UIActivity.ActivityType.copyToPasteboard, UIActivity.ActivityType.mail, UIActivity.ActivityType.message, UIActivity.ActivityType.openInIBooks, UIActivity.ActivityType.postToTencentWeibo, UIActivity.ActivityType.postToVimeo, UIActivity.ActivityType.postToWeibo, UIActivity.ActivityType.print]
} else {
// Fallback on earlier versions
activityVC.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact, UIActivity.ActivityType.copyToPasteboard, UIActivity.ActivityType.mail, UIActivity.ActivityType.message, UIActivity.ActivityType.postToTencentWeibo, UIActivity.ActivityType.postToVimeo, UIActivity.ActivityType.postToWeibo, UIActivity.ActivityType.print ]
}
if let popoverController = activityVC.popoverPresentationController {
popoverController.sourceView = self.BtnDownloadVideo
popoverController.sourceRect = self.BtnDownloadVideo.bounds
}
self.present(activityVC, animated: true, completion: nil)
}
I'm assuming when you download a file from the internet, you are sure you are downloading a video in this circumstance? And what you are really wanting is just to change the format, i.e. PathExtension such as .mp4, .png, jpeg, etc.
Iff (if and only if) this is the case, then you can add a file extension on to the path component.
let destinationURL = docDirectoryURL.appendingPathComponent("\(destinationFilename!)").appendingPathExtension("mp4")
Now, when you check your saved files, it will include the ".mp4"
Again, I'm assuming you are 110% confident you are downloading a ".mp4" from the interwebs.
I have json request which show a list of cars. I used timer to refresh the request as well as the list every 10 seconds. The problem is that the data keep adding up to the array and make my application crashes. How can I clear the data before appending new data? What should I do?
let list = listdevices[indexPath.row] // error
if list.statusxe == "run" {
cell?.devnameLabel?.text = list.devname
cell?.addressLabel?.text = list.address
cell?.statusxeLabel?.textColor = UIColor(red: 1/255, green: 117/255, blue: 0/255, alpha: 1)
cell?.statusxeLabel?.text = "Đang chạy"
cell?.speedLabel?.text = "\(list.speed) km/h"
}
else if list.statusxe == "stop"{
cell?.devnameLabel?.text = list.devname
cell?.addressLabel?.text = list.address
cell?.statusxeLabel?.textColor = UIColor(red: 230/255, green: 6/255, blue: 6/255, alpha: 1)
cell?.statusxeLabel?.text = "Đang dừng"
cell?.speedLabel?.text = ""
}
else if list.statusxe == "expired"{
cell?.devnameLabel?.text = list.devname
cell?.addressLabel?.text = list.address
cell?.statusxeLabel?.textColor = UIColor.black
cell?.speedLabel?.textColor = UIColor.black
cell?.statusxeLabel.text = " "
cell?.speedLabel?.text = "hết hạn dịch vụ"
}
else if list.statusxe == "lost_gprs"{
cell?.devnameLabel?.text = list.devname
cell?.addressLabel?.text = list.address
cell?.statusxeLabel?.textColor = UIColor.red
cell?.statusxeLabel?.text = "Mất GPRS"
cell?.speedLabel?.text = ""
}
cell?.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
return cell!
}
I have json request which show a list of cars. I used timer to refresh the request as well as the list every 10 seconds. The problem is that the data keep adding up to the array and make my application crashes. How can I clear the data before appending new data? What should I do?
let url = "http://api.vnetgps.com:8000/tracking"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
request.setValue(token , forHTTPHeaderField: "token")
request.setValue(username, forHTTPHeaderField: "username")
request.setValue("-1", forHTTPHeaderField: "devid")
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
if (error != nil ) {
print("Error")
}
else {
self.listdevices.removeAll()
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any],
let items = json?["units"] as? [[String: Any]] {
for item in items {
var lat = item["latitude"] as? String
UserDefaults.standard.set(lat, forKey: "latitude")
var long = item["longitude"] as? String
UserDefaults.standard.set(long, forKey: "longitude")
// print("long", long)
var devid = item["devid"] as? String
UserDefaults.standard.set(devid, forKey: "devid")
var devname = item["devname"] as? String
UserDefaults.standard.set(devname, forKey: "devname")
var speed = item["speed"] as? String
UserDefaults.standard.set(speed, forKey: "speed")
var statustt = item["status"] as? String
UserDefaults.standard.set(statustt, forKey: "statusxe")
var drivername = item["drivername"] as? String
UserDefaults.standard.set(drivername, forKey: "drivername")
var address = item["address"] as? String
UserDefaults.standard.set(address, forKey: "address")
var direction = item["direction"] as? String
self.listdevices.append(Listdevices(statusxe: statustt! , speed: speed!, devid: devid!, devname: devname!, address: address!, latitude: lat!, longitude: long!, drivername: drivername!, direction: direction!))
// print("list",self.listdevices)
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
})
task.resume()
}
The problem is probably that you empty the array while it is being used by the tableview.
Instead use map to replace the old array contents with the new contents. That way you don't need to empty the array first.
Something like:
self.listDevices = items.map { Listdevices($0) }
And then implement an initialiser for ListDevices like this:
init(device: [String: Any]) { ... }
A couple of unsolicited code review comments:
All the writes to UserDefaults are pointless since each iteration just overwrites the previous one, so you should just remove the whole loop.
Make statusxe into an enum StatusXE
Replace the long conditional with a switch based on the new StatusXE enum
Be careful with naming. The variable list is not a list, so don't call it that, instead maybe call it device. The variable listdevices should just be called devices or if you insist on using the word list, it should be deviceList. Also remember proper camelCasing.
Avoid force unwrapping. Possibly use the nil coalescing operator to provide default values for device properties that are null.
Avoid unnecessarily duplicating code. In the long conditional, the first two lines of code are repeated in every case. Just move those two lines out of the conditional.
I think it could be due to the async nature of your code.
try avoid self.listdevices.append and use something like :
// declare listdevices with var instead of let
let temp = [Listdevices]()
for item in items {
...
temp.append(Listdevices(statusxe: statustt! , speed: speed!, devid: devid!, devname: devname!, address: address!, latitude: lat!, longitude: long!, drivername: drivername!, direction: direction!))
}
self.listdevices = temp
I am making an app that connects to the TMDB API.
I use Hyper Sync to persist JSON to Core Data with the following code:
let completion = { (error: NSError?) in
if error == nil {
self.backdropData = [[String: AnyObject]]()
for image in movie.backdrops!.allObjects as! [Image] {
var data = [String: AnyObject]()
data[ThumbnailTableViewCell.Keys.ID] = image.filePath as String!
data[ThumbnailTableViewCell.Keys.OID] = image.objectID
if let filePath = image.filePath {
let url = "\(Constants.TMDB.ImageURL)/\(Constants.TMDB.BackdropSizes[0])\(filePath)"
data[ThumbnailTableViewCell.Keys.URL] = url
}
self.backdropData!.append(data)
}
self.posterData = [[String: AnyObject]]()
for image in movie.posters!.allObjects as! [Image] {
var data = [String: AnyObject]()
data[ThumbnailTableViewCell.Keys.ID] = image.filePath as String!
data[ThumbnailTableViewCell.Keys.OID] = image.objectID
if let filePath = image.filePath {
let url = "\(Constants.TMDB.ImageURL)/\(Constants.TMDB.BackdropSizes[0])\(filePath)"
data[ThumbnailTableViewCell.Keys.URL] = url
}
self.posterData!.append(data)
}
self.tableView.reloadData()
}
}
var data = [[String: AnyObject]]()
data.append(["id": movie.movieID!.integerValue,
"backdrops": backdrops,
"posters": posters])
let predicate = NSPredicate(format: "movieID=%# ", movie.movieID!)
Sync.changes(data, inEntityNamed: "Movie", predicate: predicate, dataStack: appDelegate.dataStack, completion: completion)
When Sync finished saving the JSON data, the backdrops are deleted and only the posters are saved in Core Data. This is not the behavior I wanted. I also want to save the backdrops in Core Data. Any way to fix this?
Here is the screenshot of my Core Data model:
For full source code, here is the link to my Github project:
Cineko
I have an application where I need to validate some information(zip code) from a database before I allow my iOS application to proceed to the next view. I used the zip code project to import a DB Table will all valid US Zip codes, and I want to have the zip code the inputed by the user validated before I allow them to proceed. If the zip code isn't valid, I hold them up at the current view and display an alert. I have a class to validate the zip code, but the zip code isn't being validated until after the next view is loaded. I've been leaning towards using a completion handler, but I'm not exactly sure if that's my best/only option. Thanks in advance.
EDIT:
The following is the whole class for retrieve the data
protocol ZipCodeLocationProtocol: class {
func zipCodeLocationDownloaded(zipLocation: Location)
}
class RetrieveZipCodeLocation: NSObject, NSURLSessionDataDelegate {
// MARK: Properties
weak var delegate: ZipCodeLocationProtocol!
var data: NSMutableData = NSMutableData()
let urlPath: String = "xxxx"
func downloadZipCodeLocation(zipcode: Int) {
let path = self.urlPath + "?zipcode=\(zipcode)"
let url: NSURL = NSURL(string: path)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
var location = Location(title: "TITLE", coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0))
do {
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:[]) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
for(var i = 0; i < jsonResult.count; i++) {
jsonElement = jsonResult[i] as! NSDictionary
let point = CLLocationCoordinate2D(latitude: (jsonElement["LATITUDE"] as! NSString).doubleValue, longitude: (jsonElement["LONGITUDE"] as! NSString).doubleValue)
// Get Information
location = Location(title: "TITLE", coordinate: point)
self.delegate.zipCodeLocationDownloaded(location)
}
}
I'm going to assume that a button triggers the segue to the next view. I'm also going to assume that the button is hooked up to a function for target-action. I'm also going to assume that you have the code to get the zip codes, otherwise you'll have to ask a separate question for that.
Assumptions aside, you need to present a UIAlertController instead of going to the next view controller when tapping the button. In order to do that:
func buttonAction() {
if verifyZipCode() {
let alert = UIAlertController(title: "Hold Up", message: "That zip code is invalid.", preferredStyle: .Alert)
let fixIt = UIAlertAction(title: "Fix It!", style: .Default, handler: nil) // handler could also contain code to make text field red or something interesting
alert.addAction(fixIt)
presentViewController(alert, animated: true, completion: nil)
} else {
// existing segue code
}
}
func verifyZipCode() -> Bool {
// Take text field text and verify zip code
}