How to store videos in Firebase using Swift - firebase

I currently have a function that allows me to upload an image to Firebase Storage. But how in the world can I achieve the same, with a video instead of an image?
I suspect I have to change UIImage and .jpg to something else. But what is the type of a video?
#State var pickedImages: [UIImage] = []
#State var retrievedImages = [UIImage]()
This is my function:
func uploadImage() {
// Create storage reference
let storageRef = Storage.storage().reference()
// Turn our image into data
let selectedImage = pickedImages[0]
let imageData = selectedImage.jpegData(compressionQuality: 0.8)
guard imageData != nil else {
let er = "THIS: Error while converting to data"
return print(er)
}
// Specifie filepath and name
let path = "images/\(UUID().uuidString).jpg"
let fileRef = storageRef.child(path)
// Upload that data
let uploadTask = fileRef.putData(imageData!, metadata: nil) {metaData, error in
print("THIS: from uploadTAsk")
// Check for errors
if error == nil && metaData != nil {
// Save reference in firestore DB
let db = Firestore.firestore()
db.collection("images").document("user1").setData(["url": path]) { error in
print("THIS: inside closure")
// If there was no errors, display the image
if error == nil {
DispatchQueue.main.async {
self.retrievedImages.append(selectedImage)
}
}
}
}
}
}

Related

Decode Cloud Firestore data result item to NSObject

I've a cloud firebase result item:
let mpUserRef = db?.collection(MPUser.PROPERTY_DB)
.whereField(MPUser.PROPERTY_FIREBASE_USER_ID, isEqualTo: firebaseUSer.uid)
.limit(to: 1).getDocuments() { (document, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in document!.documents {
let mpUser = fromJsonToMpUser( userJson: "\(document.data())" )
if mpUser != nil{
delegate.mpUser = mpUser
}
}
}
}
And i want to decode result item in my business Object calling the method:
class func fromJsonToMpUser( userJson: String ) -> MPUser?{
let decoder = JSONDecoder()
do{
let json = userJson.data(using: .utf8)!
let mpUser = try decoder.decode(MPUser.self, from: json)
return mpUser
}catch{
print("Errore while ecode Club")
return nil
}
}
But this does not work, the error message that i have is:
"The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Badly formed array around character 17." UserInfo={NSDebugDescription=Badly formed array around character 17.}))).
So, how can i converte cloud firestore item result in valid Json?
I've resolved my question using CodableFirebase library ( https://github.com/alickbass/CodableFirebase created by #alickbass )

Swift 4 Load 3D Models from Firebase

I'm trying to get a 3D Model which is stored in Firebase into my iOS Application.
Right now I stored the default Object (ship.scn) into my Firebase Storage.
How can I convert the Data, which I get from Firebase, to a SCNNode?
This is my Code right now:
let storage = Storage.storage().reference()
let modelPath = storage.child("models/ship.scn")
print("ModelPath: \(modelPath)")
modelPath.getMetadata { (metaData, error) in
if error != nil {
print("ERROR: ", error!)
}else{
print("Metadata: \(metaData!)")
}
}
// this is what firebase shows for images
// how can i get the Data as SCNNode?
modelPath.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
if error != nil {
print("Error getData: \(error!)")
}else {
print(data)
}
}
I solved this problem by downloading the 3D Object from firebase into the devices document folder.
So when I need the 3D-object I create a reference to the downloaded 3D-Object
write To Directory: (where modelPath is the storage.child('your path') in firebase)
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let tempDirectory = URL.init(fileURLWithPath: paths, isDirectory: true)
let targetUrl = tempDirectory.appendingPathComponent("ship.scn")
modelPath.write(toFile: targetUrl) { (url, error) in
if error != nil {
print("ERROR: \(error!)")
}else{
print("modelPath.write OKAY")
}
}
load 3D file from directory:
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let tempDirectory = URL.init(fileURLWithPath: paths, isDirectory: true)
let targetUrl = tempDirectory.appendingPathComponent("\ship.scn")
var sceneForNode: SCNScene? = nil
do {
// load the 3D-Model node from directory path
sceneForNode = try SCNScene(url: targetUrl, options: nil)
}catch{
print(error)
}
// create node to display on scene
let node: SCNNode? = sceneForNode?.rootNode.childNode(withName: "ship", recursively: true)

Wait for 2 callbacks before instantiating an object

I would like to download from firebase:
data issued from a group profile (Firebase realtime DB)
including...
data issued from the group admin profile (Firebase realtime DB)
a group profile image (Firebase Storage)
Then I can instantiate a group object with its data and its image
First approach, I used 3 nested closures that allowed me to get data, and then to get the image.
It did work, but it was quite long to get sequentially all that stuffs from firebase.
So I tried to use GCD in order to push my 2 latest Firebase queries (user data + group image) at the same time (rather than one after the other), and to wait for the last callback to start instantiating my group.
Is it a correct approach ?
If yes, I find some difficulties to implement it...
My issue : returnedUser and returnedGroupImage are always nil
Here is my bunch of code :
static func getGroup(_ groupID:String, completionBlock: #escaping (_ group: Group?) -> ()) {
dataRef.child("data").child("groups").child(groupID).observe(.value, with: { (snapshot) in
if let snapshotValue = snapshot.value {
guard let name = (snapshotValue as AnyObject).object(forKey: "name") as? String else
{
completionBlock(nil)
return
}
guard let adminID = (snapshotValue as AnyObject).object(forKey: "adminID") as? String else
{
completionBlock(nil)
return
}
let queue = DispatchQueue(label: "asyncQueue", attributes: .concurrent, target: .main)
let dispatch_group = DispatchGroup()
var returnedUser: User?
var returnedGroupImage: UIImage?
queue.async (group: dispatch_group) {
FireBaseHelper.getUser(adminID, completionBlock: { (user) in
if user != nil {
returnedUser = user
}
})
}
queue.async (group: dispatch_group) {
FireBaseHelper.getGroupImage(groupID, completionBlock: { (image) in
if image != nil {
returnedGroupImage = image
}
})
}
dispatch_group.notify(queue: DispatchQueue.main) {
// Single callback that is supposed to be executed after all tasks are complete.
if (returnedUser == nil) || (returnedGroupImage == nil) {
// always true !
return
}
let returnedGroup = Group(knownID: (snapshotValue as AnyObject).key, named: name, createdByUser: currentUser!)
returnedGroup.groupImage = returnedGroupImage
completionBlock(returnedGroup)
}
}
})
}
Thanks for your help !
I believe that the way you are using DispatchGroups are not correct.
let dispatch_group = DispatchGroup()
var returnedUser: User?
var returnedGroupImage: UIImage?
dispatch_group.enter()
FireBaseHelper.getUser(adminID, completionBlock: { (user) in
if user != nil {
returnedUser = user
}
dispatch_group.leave()
})
dispatch_group.enter()
FireBaseHelper.getGroupImage(groupID, completionBlock: { (image) in
if image != nil {
returnedGroupImage = image
}
dispatch_group.leave()
})
dispatch_group.notify(queue: DispatchQueue.main) {
// Single callback that is supposed to be executed after all tasks are complete.
if (returnedUser == nil) || (returnedGroupImage == nil) {
// always true !
return
}
let returnedGroup = Group(knownID: (snapshotValue as AnyObject).key, named: name, createdByUser: currentUser!)
returnedGroup.groupImage = returnedGroupImage
completionBlock(returnedGroup)
}

Firebase Storage: the uploaded image doesn't saved on the app

I upload the image via .Camera to Firebase Storage. When I closed app and run again, this image don't saved at my app. I know that I missed something. Please, tell me what I should to add. Thank's a lot!
This is my code:
import UIKit
import Firebase
import FirebaseStorage
class PicturesOfCoinsViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func saveButton(_ sender: UIButton) {
saveOneEuroCentImage()
}
#IBOutlet weak var oneEuroCentImage: UIImageView!
#IBAction func usePhotoButton(_ sender: UIButton) {
let picker = UIImagePickerController()
picker.sourceType = .camera
self.present(picker, animated: true, completion: nil)
picker.delegate = self
}
func saveOneEuroCentImage() {
let storageRef = FIRStorage.storage().reference().child("userPictures/oneEuroCent.jpg")
if let uploadData = UIImagePNGRepresentation(self.oneEuroCentImage.image!) {
storageRef.put(uploadData, metadata: nil) {(metadata, error) in
if error != nil {
print(error)
return
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
oneEuroCentImage.image = info[UIImagePickerControllerOriginalImage] as? UIImage
picker.dismiss(animated: true, completion: nil)
}
}
If you want to have a persistent copy of the image on your app then you must save the photo to your apps document directory before the upload. From your code above you are only uploading it to your cloud storage in firebase but there is no code for saving your picture locally, thats why it does not exist when the app is run again.
I suggest you create a documents directory file path or url for the image and then save it.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths.first
let imageFolderPath = path?.appending("MyFBImages")
if !FileManager.default.fileExists(atPath: imageFolderPath!){
do {
try FileManager.default.createDirectory(atPath: imageFolderPath!, withIntermediateDirectories: true, attributes: [:])
} catch let error {
print(error.localizedDescription)
}
}
let imageFilePath = imageFolderPath?.appending("myImageName.jpg")
let imageData = UIImageJPEGRepresentation(UIImage(), 1)
do {
try imageData?.write(to: URL(fileURLWithPath: imageFilePath!))
} catch let error {
print(error.localizedDescription)
}
N/B : the imageData in the code you can get that from the image you created just before the upload to firebase.
This should help you save your image locally. Next time you run your app you can access your previous images by initializing UIImage from contents of the url that holds your saved photos.
I hope this helps you out.

Downloading image on Swift 2 form Firebase Storage

Whenever I download an image from Firebase Storage it download's perfectly, but once I try to change the imageview "my" to it, the imageview disappears. I don't have constraints and I navigated to the local URL and found the image perfectly there. Any help? Am I doing something wrong?
func loadImages(){
let documentDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
let newRef = storageRef!.child("Images/0.jpg")
let fileDestinationUrl = documentDirectoryURL.URLByAppendingPathComponent("p.jpg")
let downloadTask = newRef.writeToFile(fileDestinationUrl){ (URL, error) -> Void in
if (error != nil) {
print("problem")
} else {
print("done")
}
}
downloadTask.observeStatus(.Success) { (snapshot) -> Void in
print(fileDestinationUrl)
var temp = String(fileDestinationUrl)
print(temp)
var my = UIImage(contentsOfFile: temp)
self.image.image = my
}
}
Print the destinationUrl in your console .Go to your downloaded file location , open your terminal , drag and drop the DOWNLOADED image in the terminal and the terminal will give you its actual path.Now compare both the path the one that terminal gave you and the one that console gave you, match those. most like they are to be different ,change them accordingly.
Example code :-
Uploading Code : -
func profilePictureUploading(infoOnThePicture : [String : AnyObject],completionBlock : (()->Void)) {
if let referenceUrl = infoOnThePicture[UIImagePickerControllerReferenceURL] {
print(referenceUrl)
let assets = PHAsset.fetchAssetsWithALAssetURLs([referenceUrl as! NSURL], options: nil)
print(assets)
let asset = assets.firstObject
print(asset)
asset?.requestContentEditingInputWithOptions(nil, completionHandler: { (ContentEditingInput, infoOfThePicture) in
let imageFile = ContentEditingInput?.fullSizeImageURL
print("imagefile : \(imageFile)")
let filePath = FIRAuth.auth()!.currentUser!.uid + "/\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))/\(imageFile!.lastPathComponent!)"
print("filePath : \(filePath)")
FIRControllerClass.storageRef.child("ProfilePictures").child(filePath).putFile(imageFile!, metadata: nil, completion: { (metadata, error) in
if error != nil{
print("error in uploading image : \(error)")
}
else{
print("metadata in : \(metadata!)")
print(metadata?.downloadURL())
print("The pic has been uploaded")
print("download url : \(metadata?.downloadURL())")
self.uploadSuccess(metadata!, storagePath: filePath)
completionBlock()
}
})
})
}else{
print("No reference URL found!")
}
}
Downloading code : -
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
print("paths in user home page : \(paths)")
let documentDirectory = paths[0]
print("documents directory in homePage : \(documentDirectory)")
let filePath = "file:\(documentDirectory)/\(user!.uid).jpg"
var filePath2 : String = filePath
print(filePath)
let storagePath = NSUserDefaults.standardUserDefaults().objectForKey("storagePath") as! String
print("storagePath is : \(storagePath)")
storageRef.child("ProfilePictures").child(storagePath).writeToFile(NSURL.init(string: filePath)! , completion :
{ (url, err) -> Void in
if let error = err{
print("error while downloading your image :\(error)")
}else{
print("Download successful !")
print("the file filePath of the downloaded file : \(filePath)")
filePath2 = "\(documentDirectory)/\(self.user!.uid).jpg"
if let downloadedImage = UIImage(contentsOfFile: filePath2){
self.profilePictureImageView.image = downloadedImage
print("displayed")
}else{
print("unable to display")
}
}
})
where storagePath is something that you stored in your NSUserDefaults for later reference , such as this, while uploading your image to your firebase storage
The codeBlocks that i gave you are just one of many solutions, there are plenty of ways to do this, go to https://firebase.google.com/docs/storage/ios/download-files

Resources