質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.35%

エラーコード(Value of type 'StorageMetadata' has no member 'downloadURL')を解消したい.

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 831

score 11

前提・実現したいこと

現在、Udemyでインスタグラムのクローンを作っています。(教材ページ)
しかし、Xcodeのバージョンが古いため、たくさんエラーが発生しました。そこで現在はXcode10.1にバージョンを下げてプロジェクトを作っています。Swiftのバージョンは4.2です。

FireBaseでプロフィール画像を設定するところまでなんとか進みましたが、解消できないエラーが起こりました。

発生している問題・エラーメッセージ

以下のコードを入力したら、
 guard let profileImageURL = metadata?.downloadURL()?.absoluteString else { return }
次のようなエラーが起こる!

Value of type 'StorageMetadata' has no member 'downloadURL'

該当のソースコード

import UIKit
import Firebase

class SignUpVC: UIViewController,UINavigationControllerDelegate, UIImagePickerControllerDelegate{

    var imageSelected = false


    let plusPhotoBtn: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(#imageLiteral(resourceName: "plus_photo").withRenderingMode(.alwaysOriginal),for: .normal)
        button.addTarget(self, action: #selector(handleSelectProfilePhoto), for: .touchUpInside)
        return button
    }()

    let emailTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Email"
        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.borderStyle = .roundedRect
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.addTarget(self, action: #selector(formValidation), for: .editingChanged)
        return tf
    }()

    let passwordTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Password"
        tf.isSecureTextEntry = true
        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.borderStyle = .roundedRect
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.addTarget(self, action: #selector(formValidation), for: .editingChanged)
        return tf
    }()

    let fullNameTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Full Name"
        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.borderStyle = .roundedRect
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.addTarget(self, action: #selector(formValidation), for: .editingChanged)
        return tf
    }()

    let usernameTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Username"
        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.borderStyle = .roundedRect
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.addTarget(self, action: #selector(formValidation), for: .editingChanged)
        return tf
    }()

    let signUpButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Sign Up", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = UIColor(red: 149/255, green: 204/255, blue: 244/255, alpha: 1)
        button.layer.cornerRadius = 5
        button.isEnabled = false
        button.addTarget(self, action: #selector(handleSignUp), for: .touchUpInside)
        return button
    }()

    let alreadyHaveAccountButton: UIButton = {
        let button = UIButton(type: .system)

        let attributedTitle = NSMutableAttributedString(string: "Already have an account?  ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor.lightGray])
        attributedTitle.append(NSAttributedString(string: "Sign In", attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor(red: 17/255, green: 154/255, blue: 237/255, alpha: 1)]))
        button.addTarget(self, action: #selector(handleShowLogin), for: .touchUpInside)
        button.setAttributedTitle(attributedTitle, for: .normal)

        return button
    }()



    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

        view.addSubview(plusPhotoBtn)
        plusPhotoBtn.anchor(top: view.topAnchor, left: nil, bottom: nil, right: nil, paddingTop: 40, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 140, height: 140)
        plusPhotoBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        configureViewComponents()

        view.addSubview(alreadyHaveAccountButton)
        alreadyHaveAccountButton.anchor(top: nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 50)

    }


    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        // selected image
        guard let profileImage = info[.editedImage] as? UIImage else {
            imageSelected = false
            return
        }

        // set imageSelected to true
        imageSelected = true

        // configure plusPhotoBtn with selected image
        plusPhotoBtn.layer.cornerRadius = plusPhotoBtn.frame.width / 2
        plusPhotoBtn.layer.masksToBounds = true
        plusPhotoBtn.layer.borderColor = UIColor.black.cgColor
        plusPhotoBtn.layer.borderWidth = 2
        plusPhotoBtn.setImage(profileImage.withRenderingMode(.alwaysOriginal), for: .normal)

        self.dismiss(animated: true, completion: nil)
    }



    @objc func handleSelectProfilePhoto() {

        // configure image picker
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.allowsEditing = true

        // present image picker
        self.present(imagePicker, animated: true, completion: nil)

    }



    @objc func handleShowLogin() {
        _ = navigationController?.popViewController(animated: true)
    }

    @objc func handleSignUp() {
        guard let email = emailTextField.text else { return }
        guard let password = passwordTextField.text else { return }
        guard let fullName = fullNameTextField.text else { return }
        guard let username = usernameTextField.text else { return }


        Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
            // handle error
            if let error = error {
                print("Failed to create user with error: ", error.localizedDescription)
                return
            }
            // set profile image
            guard let profileImg = self.plusPhotoBtn.imageView?.image else { return }

            // upload data
            guard let uploadData = profileImg.jpegData(compressionQuality: 0.3) else { return }

            // place image in firebase storage
            let filename = NSUUID().uuidString
            Storage.storage().reference().child("profile_images").child(filename).putData(uploadData, metadata: nil, completion: { (metadata, error) in

                // handle error
                if let error = error {
                    print("Failed to upload image to Firebase Storage with error", error.localizedDescription)
                }

                // profile image url
 //*エラーコード:Value of type 'StorageMetadata' has no member 'downloadURL'
                guard let profileImageURL = metadata?.downloadURL()?.absoluteString else { return }

            })

        }



    }






    @objc func formValidation() {

        // ensures that email and password text fields have text
        guard
            emailTextField.hasText,
            passwordTextField.hasText,fullNameTextField.hasText,usernameTextField.hasText,imageSelected == true else {

                // handle case for above conditions not met
                signUpButton.isEnabled = false
                signUpButton.backgroundColor = UIColor(red: 149/255, green: 204/255, blue: 244/255, alpha: 1)
                return
        }

        // handle case for conditions were met
        signUpButton.isEnabled = true
        signUpButton.backgroundColor = UIColor(red: 17/255, green: 154/255, blue: 237/255, alpha: 1)
    }



    func configureViewComponents() {

        let stackView = UIStackView(arrangedSubviews: [emailTextField, fullNameTextField, usernameTextField, passwordTextField, signUpButton])

        stackView.axis = .vertical
        stackView.spacing = 10
        stackView.distribution = .fillEqually

        view.addSubview(stackView)
        stackView.anchor(top: plusPhotoBtn.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 24, paddingLeft: 40, paddingBottom: 0, paddingRight: 40, width: 0, height: 240)
    }


}

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • nakasho_dev

    2019/10/28 23:58

    Udemyの教材であればUdemyの講師に質問するのが筋なのではないでしょうか?

    キャンセル

  • hameji

    2019/10/29 02:12 編集

    バージョンを下げて開発を行うのはあまりお勧めできないです。
    Xcode, swiftはバージョンアップが割と頻繁なので、
    今そのバージョンを使って開発を行っている人は少ないと思います。
    なので、その状況を再現して、検証してくれる人は少ないのでは、、、?

    バージョンの違いによる差はXcode自体から修正方法が示される事もあるので、
    慣れれば割と簡単に変換できるようになると思います。

    キャンセル

  • mansan

    2019/10/29 10:44

    nakasho_devさん
    Udemyの方で質問しても返信が全く来ないため、こちらで質問しました、、

    キャンセル

  • mansan

    2019/10/29 10:53

    hamejiさん
    バージョンを下げなくても、同じエラーが起こりました。
    こちらのエラーコードの場合、どのように変換すれば宜しいでしょうか?m(__)m

    キャンセル

回答 1

checkベストアンサー

0

古い教材を使っているのであれば、その教材に合わせたバージョンのXcodeを使うのが正しいと思います。
今の問題は、Firebase SDKのバージョンが上がってdownloadURLを取得する方法が変わっている
ことが原因です。
最新のFirebase SDKを使うのであれば、
https://firebase.google.com/docs/storage/ios/download-files?hl=ja#generate_a_download_url
の「ダウンロード URL を生成する」で説明されている方法で取得する必要があります。

そのUdemyの教材がどのようにしてFirebase SDKをセットアップするよう指示しているのか
わかりませんが、教材で使っているFirebase SDKと同じバージョンのFirebase SDKを
セットアップすれば、教材通りのコードでdownloadURLを取得できると思います。

一番いいのは最新のXcodeと最新のFirebase SDKに対応した教材を使うことだと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る