【问题标题】:Swift2 retrieving images from FirebaseSwift2 从 Firebase 检索图像
【发布时间】:2016-02-12 04:34:24
【问题描述】:

我正在尝试从 Firebase 读取/显示图像。我首先对图像进行编码,然后将此编码的字符串发布到 Firebase。这运行良好。当我尝试从 Firebase 解码编码字符串并将其转换为图像时,我得到一个 nil 值异常。

这就是我将图像保存到 Firebase 的方式

var base64String: NSString!
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {

    self.dismissViewControllerAnimated(true, completion: nil)

    imageToPost.image = image

    var uploadImage = image as! UIImage
    var imageData = UIImagePNGRepresentation(uploadImage)!
    self.base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
    let ref = Firebase(url: "https://XXX.firebaseio.com")

    var quoteString = ["string": self.base64String]
    var usersRef = ref.childByAppendingPath("goalImages")
    var users = ["image": quoteString]
    usersRef.setValue(users)

    displayAlert("Image Posted", message: "Your image has been successfully posted!")
}

这就是我尝试从 Firebase 读取图像的方式

//  ViewController.swift

import UIKit
import Firebase

class ViewController: UIViewController {
@IBOutlet weak var image: UIImageView!
var base64String: NSString!

@IBAction func buttonClicked(sender: AnyObject) {

    sender.setTitle("\(sender.tag)", forState: UIControlState.Normal)

}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let ref = Firebase(url: "https://XXX.firebaseio.com/goalImages/image/string")

    ref.observeEventType(.Value, withBlock: { snapshot in

        self.base64String = snapshot.value as! NSString
        let decodedData = NSData(base64EncodedString: self.base64String as String, options: NSDataBase64DecodingOptions())
        //Next line is giving the error
        var decodedImage = UIImage(data: decodedData!)

        self.image.image = decodedImage
        }, withCancelBlock: { error in
            print(error.description)
        })

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

错误提示:“致命错误:在展开可选值时意外发现 nil”;解码数据为零。有人可以解释出了什么问题。

【问题讨论】:

  • 试试 NSDataBase64DecodingOptions.IgnoreUnknownCharacters
  • 我遇到了同样的问题,我使用@jay 的评论修复了它。您应该写一个答案,以便询问它的用户可以将其标记为解决方案。剩下的唯一问题是解码后的图像旋转了 90 度,从水平到垂直。我也可以解决这个问题吗?
  • @eeschimosu 完成 - 转换为答案。就旋转而言......它不应该是代码本身中的某些东西导致了这种情况。我在答案中添加了一些代码作为用例。

标签: image firebase swift2


【解决方案1】:

代替

let decodedData = NSData(base64EncodedString: self.base64String as String, 
                                     options: NSDataBase64DecodingOptions())

尝试添加 IgnoreUnknownCharacters

NSDataBase64DecodingOptions.IgnoreUnknownCharacters

使用示例:对 jpg 进行编码、存储并从 firebase 读取

编码并编写我们最喜欢的星际飞船

    if let image = NSImage(named:"Enterprise.jpeg") {
    let imageData = image.TIFFRepresentation
    let base64String = imageData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
    let imageRef = myRootRef.childByAppendingPath("image_path")
    imageRef.setValue(base64String)

读取和解码

       imageRef.observeEventType(.Value, withBlock: { snapshot in

            let base64EncodedString = snapshot.value
            let imageData = NSData(base64EncodedString: base64EncodedString as! String, 
                           options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
            let decodedImage = NSImage(data:imageData!)
            self.myImageView.image = decodedImage

            }, withCancelBlock: { error in
                print(error.description)
        })

编辑 2019_05_17

更新到 Swift 5 和 Firebase 6

func writeImage() {
    if let image = NSImage(named:"Enterprise.jpg") {
        let imageData = image.tiffRepresentation
        if let base64String = imageData?.base64EncodedString() {
            let imageRef = self.ref.child("image_path")
            imageRef.setValue(base64String)
        }
    }
}

func readImage() {
    let imageRef = self.ref.child("image_path")
    imageRef.observeSingleEvent(of: .value, with: { snapshot in
        let base64EncodedString = snapshot.value as! String
        let imageData = Data(base64Encoded: base64EncodedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
        let decodedImage = NSImage(data: imageData)
        self.myImageView.image = decodedImage
    })
}

【讨论】:

  • 这很完美。唯一的问题是编码和解码需要花费大量时间并冻结应用程序。
  • Firebase 使用异步调用,因此它不应该在写入或读取数据期间冻结应用程序。话虽如此,在我的示例代码中, imageRef.setValue 可能应该在一个块中完成,以便您知道它何时完成了写入周期。另一方面,读取和解码已经在一个块中,因此它应该只解码与从 Firebase 返回的数据一样快。使用适当结构化的代码,它只会在准备好时进行编码/解码,因此冻结不应该成为问题。也许还有一个带有示例代码的问题?
【解决方案2】:

Firebase 工程师在这里:

我强烈建议使用新的 Firebase Storage API 将图像上传到 Firebase。它使用简单,成本低廉,并由 Google Cloud Storage 支持,规模巨大。

您可以从NSData 或指向本地文件的NSURL 上传(我将显示NSData,但原理相同):

// Data in memory
let data: NSData = ...

// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")

// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { metadata, error in
  if (error != nil) {
    // Uh-oh, an error occurred!
  } else {
    // Metadata contains file metadata such as size, content-type, and download URL.
    let downloadURL = metadata!.downloadURL
    // This can be stored in the Firebase Realtime Database
    // It can also be used by image loading libraries like SDWebImage
  }
}

您甚至可以暂停和恢复上传,并且可以轻松监控上传进度:

// Upload data
let uploadTask = storageRef.putData(...)

// Add a progress observer to an upload task
uploadTask.observeStatus(.Progress) { snapshot in
  // Upload reported progress
  if let progress = snapshot.progress {
    let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
  }
}

【讨论】:

  • 嗨,迈克。我目前正在使用 Firebase。如何从我的项目 Firebase 存储桶中获取图像并将其显示在 UIImageView 中?请注意,我通过 Firebase 控制台手动上传了所有图像。谢谢!
  • @brkr,您将创建对它的引用(在控制台的文件查看器中,当您单击图像时,您会在侧面板中看到一个 URL,它有一个 gs: //bucket/path/to/your/image URL),然后您可以使用它来下载数据。查看下载文档了解更多信息:firebase.google.com/docs/storage/ios/download-files
  • 太棒了!您认为为用户端保存图像的最佳方式是什么?我正在用 200 种不同类型的枪/枪皮肤构建游戏。对于新用户,他们的所有枪支都将使用默认占位符锁定。但是当他们解锁它们时,我需要更新显示的图像和数据。我应该保存到内存还是本地?图片很小,每个 70KB。
  • 有几种方法可以做到这一点:1) 将它们保存在资源包中(如果您可以在您的应用中运送 200 * 70kB = 14MB 的内容,那就太好了),2)将它们存储在静态资产服务中,例如 Firebase 托管(文件将是公开的),或者 3)将它们存储在 Firebase 存储中。使用 2 和 3,您可以使用 SDWebImage 之类的东西来执行下载并使用占位符,这里的区别将是成本和安全性(您是否关心所有文件都是公开的),而 1 是下载大小的权衡。
猜你喜欢
  • 1970-01-01
  • 2017-12-17
  • 2020-08-05
  • 1970-01-01
  • 2022-01-22
  • 2020-06-14
  • 2020-10-23
  • 2017-08-30
  • 2021-07-26
相关资源
最近更新 更多