How do you query video files from parse.com - ios

I know how to to retrieve an image file from Parse and store it in an UIImageView but how do you retrieve a video(or movie) file from Parse.com and store it in a UIView to be played (using AVPlayer) ?

Import the following in your file:
import Parse
import AVFoundation
import AVKit
add this before your class definition so that you can access it everywhere as global variables:
public var audioPlayer = AVPlayer()
public var songNumber = Int()
add this to your class definition: AVAudioPlayerDelegate
Set arrays to store the data:
var idArray = [String]()
var nameArray = [String]()
Your viewDidLoad + getSongs function:
override func viewDidLoad() {
super.viewDidLoad()
var objectQuery = PFQuery(className: "Songs")
objectQuery {
(objectsArray: [PFObject]?, error: NSError?) -> Void in
var objectIDs = objectsArray!
print(objectIDs)
for i in 0...objectIDs.count-1 {
self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)
self.nameArray.append(objectIDs[i].valueForKey("songName") as! String)
self.tableView.reloadData()
}
}
}
func getSongs () {
var songQuery = PFQuery(className: "Songs")
songQuery.getObjectInBackgroundWithId(idArray[songNumber], block: {
(object: PFObject?, error : NSError?) -> Void in
if let audioFile = object?["songFile"] as? PFFile {
let audioFileUrlString: String = audioFile.url
let audioFileUrl = NSURL(string: audioFileUrlString)!
audioPlayer = AVPlayer(URL: audioFileUrl)
audioPlayer.play()
}
})
}
After this code, you can get your getSongs function where you want, or if its a TableView then you can set it in a cell with indexPath.row
As the question is a bit broad Im giving a broad answer as I'm not sure how you want to set it and where you want to play it/under what trigger?
Here is a related question I referenced to get you started as well as the docs in Parse.
Even though the question may seem unrelated, the answer and the context is in this question/answer: Could not cast value of type PFFile to NSURL This link shows you how to query and convert so that you can play a music file.
You should also check out the Parse docs: File Queries Parse Docs

Related

Parse JSON Result To UILabel in Swift

I'm really new into swift & currently learning API by doing a project that shows list of games from rawg.io referring to the website's doc. I created GameFeed.swift & GameDetail.swift to pull name, release date, and rating from it and working fine in my console.
GameFeed.swift :
struct GameFeed: Codable {
let results:[GameDetail]
}
GameDetail.swift :
struct GameDetail: Codable {
let name:String
let released:String
let rating:Double
}
Now i'm trying to put the results to a simple UIlabel like gameName.text, gameReleased.text & gameRating.text from ViewController.swift so it will be show in Main.Storyboard
i did research on google about how to show it to these UIlabel by using DispatchQueue.main.async but when i'm declaring it, it receiving error :
Value of type 'GameFeed' has no member 'name'
same error messages also happened to released & rating. This is my ViewController.Swift :
class ViewController: UIViewController {
#IBOutlet weak var gameName: UILabel!
#IBOutlet weak var gameReleased: UILabel!
#IBOutlet weak var gameRating: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Defining API Site
let urlString = "https://api.rawg.io/api/games"
let url = URL(string: urlString)
guard url != nil else {
return
}
// Calling API
let session = URLSession.shared
let dataTask = session.dataTask(with: url!){
(data, response, error) in
if error == nil && data != nil {
let decoder = JSONDecoder()
do {
let gameFeed = try decoder.decode(GameFeed.self, from: data!)
print(gameFeed)
DispatchQueue.main.async {
self.gameName.text = gameFeed.name
self.gameReleased.text = gameFeed.released
self.gameRating.text = gameFeed.rating
}
}
catch {
print("Error Parsing JSON")
}
}
}
dataTask.resume()
}
}
What should i do to make it possible to parse the data to labels?
The GameFeed contains an Array of GameDetails. But you are trying to set a single GameDetail on those labels. You should first pull out a single GameDetail from that array, then assign it in a way you like.
DispatchQueue.main.async {
let gameDetail = gameFeed.results.first // <- This will return the first one
self.gameName.text = gameDetail?.name
self.gameReleased.text = gameDetail?.released
self.gameRating.text = gameDetail?.rating
}

How retrieve values from an object on Cloud Firestore? Swift

I'm quite new on Firestore and Firebase libraries. Can someone explain how could I retrieve the fields from my object and stored in a variable on my code? I'm trying to access all the latMin, latMax, lonMin, and lonMax from each object in my Firestore, as well if is a way to retrieve each field with the same name (ex. latMin from place 1 and 2). I don't know if this is possible or maybe there is a better way to have organized my Firebase.
Here is my Cloud Firebase: Here is the image for my Firestore, requested in the comments.
place 1: //This is an Object in my Firestore
//Field = Number : Value ----> This is how object is orginazed
latMax : 39.727
latMin : 39.726
lonMax : -121.7997
lonMin : -121.8003
place 2:
latMax : 39.7559
latMin : 39.755
lonMax : -122.1988
lonMin : -122.1992
I was able to access the objects without any problem, this is the function I'm using to read the documents on my Firestore:
import UIKit
import FirebaseFirestore
import Firebase
import CoreLocation
class SecondViewController: UIViewController, CLLocationManagerDelegate {
//Creating access to locationManager
var locationManager : CLLocationManager!
#IBOutlet weak var latLabel: UILabel!
#IBOutlet weak var lonLabel: UILabel!
#IBOutlet weak var place: UILabel!
#IBOutlet weak var placeImage: UIImageView!
//Storing the pass data that we got from the firt View
var lonStore = String()
var latStore = String()
var fireLon = String()
var fireLat = String()
var lonNumberStore = Double()
var latNumberStore = Double()
var fireLonMax = Double()
var fireLatMax = Double()
var fireLonMin = Double()
var fireLatMin = Double()
override func viewDidLoad() {
//Here goes some code to display on the SecondViewController
readArray()
}
func readArray() {
let placeRef = Firestore.firestore().collection("places")
placeRef.getDocuments { (snapshot, error) in
guard let snapshot = snapshot else {
print("Error \(error!)")
return
}
for document in snapshot.documents {
let documentId = document.documentID
let latMax = document.get("latMax") as! String //Getting a nil error
print(documentId, latMax) //This print all objects
}
}
}
I'm missing something and I know it, the problem is that I can't find any reference of what I need to do in this case, I had read the documentation like 50 times and I can't find the solution. Thanks for taking the time to read my post.
Your readArray code is SUPER close. Just need to add code to read the individual fields within the document
func readArray()
self.db.collection("places").getDocuments { (snapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in snapshot!.documents {
let docId = document.documentID
let latMax = document.get("latMax") as! String
let latMin = document.get("latMin") as! String
let lonMax = document.get("lonMax") as! String
let lonMin = document.get("lonMin") as! String
print(docId, latMax, latMin, lonMax, lonMin)
}
}
}
The problem in the original question is the structure of the database. Here's a structure that will match the code in my answer and will be better suited for what the OP wants to accomplish.
The structure in the question has multiple places listed under one collection - that's OK but it groups the places together. If we change that to have one place per collection, it makes iterating over them and getting to the data much easier.
I think your places model have references to two objects bestBuy and house. So, the retrieval approach would be to retrieve the data from and store in the object only. Means you can directly set all the data in plcaes model. Then you can call getter methods of bestBuy and house to retrieve the data as you want. Here is a sampe code (here it is retrieving only one document) but you can apply the same for all documents by iterating a for loop and converting each document to object:-
let docRef = db.collection("cities").document("BJ")
docRef.getDocument { (document, error) in
if let city = document.flatMap({
$0.data().flatMap({ (data) in
return City(dictionary: data)
})
}) {
print("City: \(city)")
} else {
print("Document does not exist")
}
}
But according to firestore documentation the best way to store nested objects is creating a subcollection and then storing it in its document.
Some clarification since the iOS Firestore documentation is, IMO, light in many areas: there are two ways to retrieve the values from a document field (once the document has been gotten)--using a Firestore method (per the documentation) and using Swift's native method of getting values from dictionaries.
let query = Firestore.firestore().collection("zipCodes").whereField("california", arrayContains: 90210)
query.getDocuments { (snapshot, error) in
guard let snapshot = snapshot,
error == nil else {
return print("error: \(error!)")
}
guard !snapshot.isEmpty else {
return print("results: 0")
}
for doc in snapshot.documents {
// using firestore's convention
if let array = doc.get("zipCodes") as? [Int] {
if array.contains(90211) {
// doc contains both zip codes
}
}
// using swift's convention
if let array = doc.data()["zipCodes"] as? [Int] {
if array.contains(90211) {
// doc contains both zip codes
}
}
}
}
Personally, I would use as much of Firestore's framework as possible for safety and predictability and, therefore, use get() for all field retrieval.

lable.text - Fatal Error

I have 2 classes.
In first class I have a label and a button and in second class I have JsonPars function
I need to write a data from second class to the label in first class.
Here is my code:
import UIKit
import CoreLocation
//main class
class ViewController: UIViewController{
#IBOutlet weak var labl: UILabel!
#IBAction func btn(sender: AnyObject) {
Json().Pars()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
and second class:
import Foundation
//Json-class
class Json {
func Pars() {
let url = NSURL(string: "http://my.url.com")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if (error != nil){
println(error.localizedDescription)
}
var err: NSError?
let parseObj: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: &err)
if let json = parseObj as? NSDictionary{
if let response = json["response"] as? NSDictionary{
if let obj = response["Object"] as? NSDictionary{
if let data = obj["data"] as? NSString {
println(data)//work's and i have a data
ViewController().labl.text = data //fatal error: unexpectedly found nil while unwrapping an Optional value
}
}
}
}
})
task.resume()
}
}
Sorry fo my English
The problem is you're creating a new instance of ViewController when you call ViewController(). Since you haven't presented the view controller it's outlets haven't been set and are nil. Therefore when you try to access labl (an implicitly unwrapped optional), it's equal to nil and your app crashes.
To fix this, perhaps pars() (it's convention to use lower case for methods) could return the data, which you would then have access to in your ViewController class.
Sorry I'm in class on my Lenovo so I can't test this, but try:
import Foundation
import UIKit
I normally do that just in case I need it at some point. Also if that fails maybe try sending data to the viewcontroller then applying it to label.text.
EDIT: You also have this:
})
above task.resume, please review that and see if that doesn't fix it.

How to add PFObjects to a tableview in swift

I am building a checkin app, and am having trouble filling my tableview with guests stored using Parse. I get an error when trying to append the objects. I also have a user login that I followed from a Udemy course. In the course he showed how to display PFUsers, but I can't get it to work using PFObjects. Any help would be great on this.
Here is the working code with PFUsers.
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query!.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var user:PFUser = object as! PFUser
self.users.append(user.username!)
}
self.tableView.reloadData()
})
}
And here is the nonworking code with PFObjects.
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "TestObject")
query.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var guest = object as! PFObject
self.users.append(guest.foo!)
}
})
}
The error shows on the line
self.users.append(guest.foo!)
And the error says "'PFObject' does not have a member named 'foo'"
You define your PFUser object with the variable user, this will make the first example work (you get the name of the user) The second example doesn’t work cause you still define the PFObject as user but try to access the name of guest which is not defined.
You could either go with the first example or change
var user:PFObject = object as! PFObject
With
var guest:PFObject = object as! PFObject
Either way, it doesn’t matter for your code, it is just the name of the variable.
This explanation will fix your “Use of unresolved identifier ‘guest’”
But this isn’t your only problem,
the PFUser object which the first example uses is a special kind of a PFObject, the PFUser class does have a .name which refers to (obviously) the name of the user. Not every PFObject has a name though so you can’t just access the .name of a PFObject. Parse has an excellent documentation about retrieving objects I would first access this documentation. If this is still unclear to you, you can open another specific question about your new problem.
To retreive the data from an object you need to use []
Let’s suggest we have a class named gameScore with the following info
score: 1337, playerName: “Sean Plott”, cheatMode: false
We would do that as follows
var gameScore = PFObject(className:"GameScore")
gameScore["score"] = 1337
gameScore["playerName"] = "Sean Plott"
gameScore["cheatMode"] = false
gameScore.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// The object has been saved.
} else {
// There was a problem, check error.description
}
}
To retrieve the object you need to query (as you already did in your post)
Ones you’ve received the data you can extract it as follows:
let score = gameScore["score"] as Int
let playerName = gameScore[“playerName"] as String
let cheatMode = gameScore["cheatMode"] as Bool
I figured it out, I needed to get the object label as a string before I could append it to the array to then add it to the tableview.
Here is the working code:
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "TestObject")
query.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var foo = object.objectForKey("foo") as? String
self.users.append(foo!)
}
self.tableView.reloadData()
})
}

Fetch Record Assets in CloudKit Using Swift

I am new to CloudKit and I am having trouble connecting the assets in my database to the ImageView and TextView in my app. In my CloudKit database, under record types, I created a record named "Companies". I then went to Public Data->Default Zone and then created a new instance of the record called "myCompany". In "myCompany" I have two assets, an image and a .txt file. I want to connect those assets to my app. I am not sure if I need to use CKQuery or what is the best approach. Any advice would be much appreciated. Below is what I have so far. Feel free to give feedback of what I have or if there's a better way, I would love to know. Thanks.
import UIKit
import CloudKit
class LearnViewController: UIViewController {
#IBOutlet weak var theImage: UIImageView!
#IBOutlet weak var theText: UITextView!
let myRecord = CKRecord(recordType: "Companies" )
var image: UIImage!
let database = CKContainer.defaultContainer().publicCloudDatabase
func loadCoverPhoto(completion:(photo: UIImage!) -> ()) {
dispatch_async(
dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)){
var image: UIImage!
let coverPhoto = self.myRecord.objectForKey("Picture") as CKAsset!
if let asset = coverPhoto {
if let url = asset.fileURL {
let imageData = NSData(contentsOfFile: url.path!)!
image = UIImage(data: imageData)
}
}
completion(photo: image)
}
}
override func viewDidLoad() {
super.viewDidLoad()
loadCoverPhoto() { photo in
dispatch_async(dispatch_get_main_queue()) {
self.theImage.image = photo
}
}
You could get the record directly if you know the recordId by performing a fetch like:
database.fetchRecordWithID(CKRecordID(recordName: recordId), completionHandler: {record, error in
Or if you don't know the ID you should query for the record with something like the code below. just create the right NSPredicate. A query can return more than 1 record.
var query = CKQuery(recordType: recordType, predicate: NSPredicate(value: true))
var operation = CKQueryOperation(query: query)
operation.recordFetchedBlock = { record in
// is this your record...
}
operation.queryCompletionBlock = { cursor, error in
self.handleCallback(error, errorHandler: {errorHandler(error: error)}, completionHandler: {
// ready fetching records
})
}
operation.resultsLimit = CKQueryOperationMaximumResults;
database.addOperation(operation)
In your case when using the fetchRecordWithID option the code would look like this:
override func viewDidLoad() {
super.viewDidLoad()
database.fetchRecordWithID(CKRecordID(recordName: recordId), completionHandler: {record, error in
self.myRecord = record
loadCoverPhoto() { photo in
dispatch_async(dispatch_get_main_queue()) {
self.theImage.image = photo
}
}
}
}

Resources