34055

[code]

    func uploadImageToStorage(image: UIImage) -> String? {
    
            let imageName = NSUUID().uuidString + ".jpg"
    
            var url: String?
    
            if let complessionImage = UIImageJPEGRepresentation(image, 0.1) {
    
                let ref = FIRStorage.storage().reference().child("profileImages").child(imageName)
    
                ref.put(complessionImage, metadata: nil, completion: { (metadata, error) in
    
                    if error != nil {
                        return
                    }
    
    
                    url = metadata?.downloadURL()?.absoluteString
                })
            }
            return url
        }
    
[/code]

これを実行するとref.putの中ではちゃんと変数urlにURLが代入されているのに、returnするときにはnilになっている。  
変数urlにURLを代入してreturnするにはどうしたらいいのでしょうか？


CC BY-SA 3.0
2017-04-16T14:40:10.057
34054
2017-04-16T22:57:37.897
2017-04-16T14:45:22.487
22590
22590
question
ios xcode swift3 firebase
FirebaseからStorageに画像をアップロードするときにURLが取得できない


あなたが使用している`put(_:metadata:completion:)`は非同期処理であり、その`completion:`パラメータに渡したクロージャー`{(metadata,
error) in ... }`は、処理の完了後に起動されます。従って、`return
url`を実行した時点ではアップロード処理は完了していないはずですから、`uploadImageToStorage(image:)`は常に`nil`を返す、と言うことになります。

「非同期処理の結果を戻り値として返したい」などのキーワードで検索すれば、様々な記事が見つかるかと思います。探し方によっては「一応動いているように見えるかもしれないが、酷いコード」が上位にヒットすることもあるので注意しないといけませんが、一番確実かつ一般的なのは、完了ハンドラーパターンにすることでしょう。

メソッドに完了ハンドラー引数をもたせ、メソッドそのものからは戻り値を返さないようにします:

[code]

    func uploadImageToStorageAsync(_ image: UIImage, completion: @escaping (String?, Error?)->Void) {
    
        let imageName = UUID().uuidString + ".jpg"
    
        if let complessionImage = UIImageJPEGRepresentation(image, 0.1) {
    
            let ref = FIRStorage.storage().reference().child("profileImages").child(imageName)
    
            ref.put(complessionImage, metadata: nil, completion: { (metadata, error) in
    
                if error != nil {
                    completion(nil, error)
                }
    
    
                let urlString = metadata?.downloadURL()?.absoluteString
                completion(urlString, nil)
            })
        }
    }
    
[/code]

使う場合は、こんな風に呼び出します。

[code]

    uploadImageToStorageAsync(anImage) {urlString, _ in
        //`urlString`を使用した処理
        //...
    }
    
[/code]

慣れるまでは少しわかりにくいかもしれませんが、非常によく使われているパターンなので、慣れてくればこの方が普通に感じられるようになるかと思います。

(こちらでFirebaseの動作確認ができる環境までは作れていないので、コードについては若干修正していただく必要があるかもしれませんが、考え方は上記の形で問題ないはずです。)


CC BY-SA 3.0
2017-04-16T22:57:37.897
34055
2017-04-16T22:57:37.897
13972
34054
answer