Diplomatic Medic Diplomatic Medic - 1 month ago 53
iOS Question

Firebase Upload Image to Storage During User Registration

I'm new to Firebase, and I have been following their documentation here.
However, nothing I have tried seems to work.

What I am trying to do:

1) Register a user -Works

2) Have the user choose a profile picture during the registration process -Doesn't work.

The code:

- (void) registerNewUser:(FIRUser *)user

{
FIRUser *currentUser = [FIRAuth auth].currentUser;
NSString *email = emailAddressTxtField.text;
NSString *password = passwordTxtField.text;
NSString *username = usernameTxtField.text;
[[FIRAuth auth]
createUserWithEmail:email
password:password
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error)
{
if (error)
{
NSLog(@"%@", error.localizedDescription);
return;
}
else
{
////ASSIGN NEW USER THEIR NAME////
self.databaseRef = [[FIRDatabase database] reference];
[[[databaseRef child:@"users"] child:user.uid]
setValue:@{@"name": username}];
}
}];
////ESTABLISHED A USER, SO LET'S ASSIGN THEIR PIC TO THEM////
if (profilePicImageView.image)
{
FIRStorageReference *profilePicRef = [[storageRef child:@"images/profilePicture.jpg"] child:currentUser.uid];
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";
NSData *imageData = UIImageJPEGRepresentation(self.profilePicImageView.image, 0.8);
NSLog(@"metadata from image: %@", metadata);

[profilePicRef putData:imageData metadata:metadata completion:^(FIRStorageMetadata *metadata, NSError *error)
{
if (error != nil)
{
NSString *profileImageURL = metadata.downloadURL.absoluteString;
NSLog(@"Profile Image URL from image: %@", profileImageURL);
[ProgressHUD showSuccess:[NSString stringWithFormat:@"%@ Successfully Registered!!", username]];
[self.segmentedLoginRegister setSelectedSegmentIndex:0];
[self checkSegmentedControl];
[ProgressHUD showSuccess:[NSString stringWithFormat:@"Welcome %@!", username]];
}
else
{
NSLog(@"Failed to Register User with profile image");
}
}];
}
}


Additional Information:

Photos are coming only from the camera roll of the user's device
Debug area prints:


[Generic] Creating an image format with an unknown type is an error

Answer

HOW TO REGISTER A USER

Let's assume that you have 3 textfields to register a user. You have a usernameTextfield, an emailTextField, and a passwordTextfield. We also want to have a profilePicture associated with this user. So we first:

Established a method to save our values for our User to the Firebase Database:

-(void) saveValuesForUser:(FIRUser *) user
{
    NSString *username = usernameTxtField.text;
    self.databaseRef = [[FIRDatabase database] reference];
    [[[databaseRef child:@"users"] child:user.uid]
     setValue:@{@"Name": username, @"Profile Picture": profileImageURL}];
}

The profileImageURL above is an NSString that you can create above your implementation of your view controller, but we also should create a UIImage that we can access throughout the ViewController:

#import "ViewController.h"
@import Photos;
@interface ViewController ()

@end

NSString *profileImageURL;
UIImage *profileImage;

@implementation ViewController

I'm guessing that you know how to launch the camera roll off from a UIButton but in case you do not, let's call these methods so that when our user taps the button to choose their image that it get's set to our profilePicture.imageView:

- (IBAction)chooseImageAction:(id)sender

{
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [self presentViewController:picker animated:YES completion:NULL];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info

{
    picker.delegate = self;
    profileImage = info[UIImagePickerControllerEditedImage];
    profilePicImageView.image = profileImage;
    [self dismissViewControllerAnimated:NO completion:nil];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

{
    [picker dismissViewControllerAnimated:YES completion:NULL];
}

Now we're cooking with fire! Now that we have the image the user wants to upload for their profilePicture, let's create a method to save it as an NSURL to our Firebase Database:

- (void) saveProfileImage

{
    FIRUser *currentUser = [FIRAuth auth].currentUser;
    NSString *username = usernameTxtField.text;

    if (profilePicImageView.image != nil)
    {
        FIRStorage *storage = [FIRStorage storage];
        storageRef = [storage referenceForURL:@"gs://PUTYOURFIREBASEHERE.appspot.com"];
        NSString *imageID = [[NSUUID UUID] UUIDString];
        NSString *imageName = [NSString stringWithFormat:@"Profile Pictures/%@.jpg",imageID];
        FIRStorageReference *profilePicRef = [storageRef child:imageName];
        FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
        metadata.contentType = @"image/jpeg";
        NSData *imageData = UIImageJPEGRepresentation(self.profilePicImageView.image, 0.8);        
        [profilePicRef putData:imageData metadata:metadata completion:^(FIRStorageMetadata *metadata, NSError *error)
         {
             if (!error)
             {
                 profileImageURL = metadata.downloadURL.absoluteString;
                 [self saveValuesForUser: currentUser];
             }
             else if (error)
             {
                 NSLog(@"Failed to Register User with profile image");
             }
         }];
    }
}

IMPORTANT: Make sure you insert your gs:// reference for the value of storageRef! You can find this on your Firebase Console under Storage.

Now that we have the method to save the user's profile picture, let's create a method to Register the new user that we can call it on our IBAction:

- (void) registerNewUser

{
    NSString *email = emailAddressTxtField.text;
    NSString *password = passwordTxtField.text;
    [[FIRAuth auth]
     createUserWithEmail:email
     password:password
     completion:^(FIRUser *_Nullable user,
                  NSError *_Nullable error)
     {
         if (error)
         {
             NSLog(@"%@", error.localizedDescription);
             return;
         }
         else
         {
             [self saveProfileImage];
         }
     }];
}

Oh thats nice! Now, let's call that method on our button, so that when the user taps the Register button on our UI, that it get's called:

- (IBAction)registerUserAction:(id)sender
{

[self registerNewUser];

}

Note: Make sure that in your ViewController.h file that you are setting the appropriate delegates:

@interface ViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate>
Comments