I'm trying to upload an image to the Firebase storage. This is what I have so far:
fileprivate func uploadImageToFirebase(){
let storageRef = Storage.storage().reference()
guard let uploadData = imageToUpload?.pngData() else { return }
storageRef.putData(uploadData, metadata: nil) { (metadata, err) in
if err != nil {
print(err?.localizedDescription)
return
}
print(metadata)
}
}
uploadData is not nil, but my app crashes. this is what I get:
reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1]'
I tried to look up, but couldn't understand why the app crash and how to fix it.
I got it that I'm trying to insert a nil, but I don't have anything nil.
I got it to work, this is what I have now:
fileprivate func uploadImageToFirebase(completion: #escaping((_ url: String?)->())){
let imageName = UUID().uuidString
let storageRef = Storage.storage().reference()
let imagesRef = storageRef.child(imageName)
guard let uploadData = imageToUpload?.jpegData(compressionQuality: 0.8) else { return }
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
imagesRef.putData(uploadData, metadata: metaData) { (metadata, err) in
if err == nil && metadata != nil {
imagesRef.downloadURL(completion: { (url, err) in
guard let downloadUrl = url else { return }
let urlString = downloadUrl.absoluteString
completion(urlString)
})
}
completion(nil)
}
}
EDIT:
The problem with the code in the question was there was no name assigned to the file to upload. In other words
let storageRef = Storage.storage().reference()
is a reference to the storage itself, but when uploading to storage there needs to be a filename like this
let storageRef = Storage.storage().reference()
let myFile = storageRef.child("my_cool_pic.jpg")
and the use is
myFile.putData(uploadData, metadata: nil)...
Related
I'm trying to upload a video file using phpickerviewcontroller, but I'm running into an issue uploading the URL to FirebaseStorage. Here is some code:
func uploadVideo(videoURL: URL)
{
let storage = Storage.storage()
let storageRef = storage.reference()
let videoRef = storageRef.child("rPosts/\(uid!)/\(fileID)")
let metadata = StorageMetadata()
metadata.contentType = "video/quicktime"
var videoData: Data = Data()
do
{
videoData = try Data(contentsOf: videoURL)
}
catch
{
print(error.localizedDescription)
return
}
videoRef.putData(videoData, metadata: metadata)
{ (metaData, error) in
guard error == nil else
{
self.errorLabel.text = error!.localizedDescription
return
}
}
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
{
dismiss(animated: true, completion: nil)
guard let itemProvider = results.first?.itemProvider else { return }
itemProvider.loadItem(forTypeIdentifier: "com.apple.quicktime-movie", options: nil)
{ (videoFile, error) in
guard error == nil else { return }
let videoFile = videoFile as? URL
DispatchQueue.main.async
{
self.uploadVideo(videoURL: videoFile!)
print(videoFile!)
}
self.uploadedYet = true
}
}
I've tried using .putFile but it keeps on saying
Ensure file URL is not a directory, symbolic link, or invalid url.
When I use .putData it says
The file "..." couldn’t be opened because there is no such file
EDIT:
itemProvider.loadFileRepresentation(forTypeIdentifier: "com.apple.quicktime-movie")
{ (videoURL, error) in
guard error == nil else { return }
print("isbeingcalled") //does not get calleed :(
DispatchQueue.main.async
{
let storageRef = Storage.storage().reference()
let videoRef = storageRef.child("rPosts/\(self.uid!)/\(self.fileID).mov")
let metadata = StorageMetadata()
metadata.contentType = "video/quicktime"
print("run")
videoRef.putFile(from: videoURL!, metadata: metadata)
{ (metaData, error) in
guard error == nil else
{
print(videoURL!)
print(videoRef.fullPath)
self.errorLabel.text = error!.localizedDescription
print(error!.localizedDescription)
return
}
}
}
self.uploadedYet = true
}
func uploadImage(){
let data = Data()
let storage = Storage.storage()
let storageRef = storage.reference()
let imagesRef = storageRef.child(imageView.image) //not sure how it's done
let uploadTask = imagesRef.putData(data, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
return
}
let size = metadata.size
imagesRef.downloadURL { (url, error) in
guard let downloadURL = url else {
return
}
}
}
}
Hi,I'm new to xcode. I would love to know how to upload image displayed on uiimageview to firebase when the above function is called.
you can do something like this:
func uploadImage(img1 :UIImage){
var data = NSData()
data = UIImageJPEGRepresentation(img1!, 0.8)! as NSData
// setting the upload path
// then choose the path where you want to store the image in the storage
let filePath = "\(userid)"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef = FIRStorage.storage().reference()
self.storageRef.child(filePath).put(data as Data, metadata: metaData){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
}else{
//Storing the downloadURL..
let downloadURL = metaData!.downloadURL()!.absoluteString
}
}
}
func uploadProfileImage(_ image:UIImage, completion: #escaping ((_ url:URL?)->())) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storageRef = Storage.storage().reference().child("user/\(uid)")
let imageData = image.jpegData(compressionQuality: 0.75)
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
storageRef.putData(imageData!, metadata: metaData)
//Get url
let imageRef = storageRef
imageRef.downloadURL { url, error in
if let error = error {
print(error.localizedDescription)
}else{
print(url.absoluteString)
}
}
}
The code inside will not execute, it will skip everything and act like there is no code stored. I am unsure how completions work but I would imagine it would either print the error or print the url but it does neither. When I set a breakpoint here it doesn't even bother checking if error = error. Is there something I did wrong or anyone else having the same problem?
imageRef.downloadURL { url, error in
if let error = error {
print(error.localizedDescription)
}else{
print(url.absoluteString)
}
}
Your putData:metadata:completion: doesn't have completion block. You can access to download URL after upload so putData should be look like this.
storageRef.putData(imageData!, metadata: metaData) { (metadata, error) in
guard let metadata = metadata else {
// an error occurred!
return
}
// Metadata contains file metadata such as size, content-type.
let size = metadata.size
// You can only access to download URL after upload.
let imageRef = storageRef
imageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
// an error occurred!
return
}
}
}
Your API call is asynchronic so that why you need instead of print actually use completion block to return the result (error or value).
I'm trying to create a function that uploads images to Firebase Storage and returns the download url for their path so I can use it other parts of the app.
This is what the function looks like:
func uploadImage(to reference:StorageReference, image:UIImage) -> URL? {
let imageData = UIImageJPEGRepresentation(image, 0.2)
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
var downloadURL = metadata.downloadURL()
reference.putData(imageData!, metadata: metadata) { (metadata, error) in
if error != nil {
print("Couldnt upload due to \(String(describing: error))")
}
downloadURL = metadata?.downloadURL()
}
return downloadURL!
}
I can't seem to get the result that I want as downloadUrl always returns nil. What am I doing wrong?
The problem here is that your function is returning before the upload is complete. In other words your function needs to return a callback, rather than a plain URL. Something like -
func uploadImage(to reference:StorageReference, image:UIImage, completion: #escaping (URL?) -> Void) {
let imageData = UIImageJPEGRepresentation(image, 0.2)
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
var downloadURL = metadata.downloadURL()
reference.putData(imageData!, metadata: metadata) { (metadata, error) in
if error != nil {
print("Couldnt upload due to \(String(describing: error))")
completion(nil)
} else {
if let downloadUrl = metadata?.downloadURL() {
completion(downloadUrl)
} else {
completion(nil)
}
}
}
}
I am getting facebook's profile picture and displaying it as the profile picture in my app. Here is the code.
if let user = FIRAuth.auth()?.currentUser{
let photoUrl = user.photoURL
let name = user.displayName
self.FacebookUser.text = name
let storage = FIRStorage.storage()
//refer your particular storage service
let storageRef = storage.reference(forURL: "gs://gsignme-14416.appspot.com")
let profilePicRef = storageRef.child(user.uid+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) -> Void in
if (error == nil){
self.FacebookPic.image = UIImage(data: data!)
}else{
print("Error downloading image:" )
}
})
if(self.FacebookPic.image == nil)
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height": 300, "width": 300, "redirect": false], httpMethod: "GET")
profilePic?.start(completionHandler: {(_ connection, result, error) -> Void in
// Handle the result
if error == nil {
if let dictionary = result as? [String: Any],
let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String{
if let imageData = NSData(contentsOf: NSURL(string: urlPic)!as URL){
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil) {
metadata, error in
if (error == nil)
{
let downloadurl = metadata!.downloadURL
}
else
{
print("Error in downloading image")
}
}
self.FacebookPic.image = UIImage(data: imageData as Data)
}}}})}
}else{
}
//The END of the Facebook user and picture code
I was able to get it working for a couple days and now it doesn't work anymore, I have gone through it line by line and I honestly can't figure out why it is not working.
I used this code:
func pictureFromFirebase(loginMethod: Int)
{
if loginMethod == 0 //FB
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height":300, "width":300, "redirect":false], httpMethod: "GET")
let profilePicRef = storageRef.child((user?.uid)!+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
// but we don't need to do anything yet. Try to download the profile pic
}
if (data != nil)
{
print("no need to download image from facebook")
self.profileImage.image = UIImage (data: data!)
}
else
{
// THIS IS THE BLOCK THAT HAS BEEN MOVED
// WHICH WILL NOW BE EXECUTED IN TWO CONDITIONS -
// 1. AN ERROR IN THE DOWNLOAD
// 2. NO PROFILE PIC AVAILABLE
print("downloading image from facebook")
profilePic?.start(completionHandler: {(_ connection, _ result, _ error) -> Void in
if (error == nil)
{
if let dictionary = result as? [String:Any], let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String {
if let imageData = NSData(contentsOf: NSURL(string: urlPic)! as URL)
{
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil){
metadata, error in
if (error == nil)
{
let downloadUrl = metadata!.downloadURL
}
else
{
print("error in downloading image")
}
}
self.profileImage.image = UIImage(data: imageData as Data)
}
}
}
})
}
}
}
}
from this post Second If statement gets called before first statement finished in one function and it worked
you just get your facebook profile pic. using this url and put the url in your UIImageview
let profilepicURl = "https://graph.facebook.com/\(user_id_fb)/picture?type=large" //user_id_fb like 1251246454544 your facebook ID