当我单击“保存” ...任何想法时,应用程序正在崩溃。

时间:2019-05-24 15:11:38

标签: ios swift firebase

我有一个回忆写应用程序,在该应用程序中,您可以创建包含标题,正文,图片和日期(直到日期都有倒数)的回忆。直到我添加了这些与日期相关的代码行,它的工作状况都很好。现在,当我尝试保存新内存时,应用程序崩溃(“线程1:信号SIGABRT”)。你知道如何解决这个问题吗?

我在下面的代码中添加了内存类和AddMemoryViewController:

内存类别:

import Foundation
import Firebase

class Memory {
    var title: String
    var uid: String  // user id
    var body: String
    var key:String
    var imageRef:String!
    var image:UIImage?
    var date = Foundation.Date()

    init( title:String , body:String , key:String = "", uid:String , imageRef:String , date:Foundation.Date ) {

        self.title = title
        self.key = key
        self.body = body
        self.uid = uid
        self.imageRef = imageRef
        self.key = ""
        self.date = date
    }

    func toAnyObject()-> [String:AnyObject] {
        return ["title" : self.title as AnyObject,"body":self.body as AnyObject,"uid":self.uid as AnyObject,"imageRef":self.imageRef as AnyObject, "date":self.date as AnyObject]

    }
}

AddMemoryViewController:

import UIKit

导入Firebase 导入FirebaseAuth 进口FirebaseDatabase

AddMemoryViewController类:UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {

var ref : DatabaseReference!
let sref = Storage.storage().reference()

var m : Memory!
var imgref : String?
var picker : UIImagePickerController? = nil

//vars for edit mode

var current : Memory!
var mode : String! // new Memory = newMemory , edit = edit

 let currentTime = NSDate().timeIntervalSince1970 * 1000
var future = Date()

var dateToSet:两倍

// connections from storyboard to the code

@IBOutlet weak var countLabel: UILabel!

@IBAction func datePickerChanged(_ sender: UIDatePicker) {
     future = sender.date
    //Use midnight today as the starting date
    guard let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date()) else { return }

    //Calculate the number of days between today and the =user's chosen day.
    let difference = Calendar.current.dateComponents([.day], from: today, to: future)
    guard let days = difference.day else { return }
    let ess = days > 1 ? "s" : ""
    countLabel.text = "That date is \(days) day\(ess) away."
}


var datePicker = UIDatePicker()

// connections from storyboard to the code

@IBOutlet weak var txtTitle: UITextField!
@IBOutlet weak var tBody: UITextView!
@IBOutlet weak var ivImage: UIImageView!

@IBAction func addPicLibrary(_ sender: UIButton) {
    picker?.allowsEditing = false

    picker?.sourceType = UIImagePickerController.SourceType.photoLibrary

    picker?.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!

    picker?.modalPresentationStyle = .popover

    present(picker!,animated: true, completion: nil)
}

@IBAction func addPicCamera(_ sender: UIButton) {
    if UIImagePickerController.availableCaptureModes(for: .rear) != nil {

        picker?.allowsEditing = false

        picker?.sourceType = UIImagePickerController.SourceType.camera

        picker?.cameraCaptureMode = .photo

        picker?.modalPresentationStyle = .fullScreen

        present(picker!,animated: true,completion: nil)

    } else {

        noCamera()

    }
}

// alert when device has no camera
func noCamera() {

    let alertVC = UIAlertController(title: "No Camera",message: "Sorry, this device has no camera",preferredStyle: .alert)

    let okAction = UIAlertAction(title: "OK",style:.default,handler: nil)

    alertVC.addAction(okAction)

    present(alertVC,animated: true,completion: nil)

}

// Function to edit a Memory

func editNewMemory()
{
    let currentKey = ref.child("MEmories/\(self.current.key)")

    self.current.body = tBody.text!

    self.current.title = txtTitle.text!

    imgref = "\(txtTitle.text!).png"

    self.current.imageRef = imgref

    dateToSet = self.future.millisecondsSince1970

    self.current.date = self.dateToSet

    currentKey.setValue(current.toAnyObject())

    self.saveImage()

    self.saveToNSUserDefaualts(memory: self.current)


}

// Function to add a new Memory

func addNewMemory()
{
    let refposts = ref.child("MEmories").childByAutoId()

    imgref = "\(txtTitle.text!).png"
    self.m = Memory(title: txtTitle.text!, body: tBody.text!, key: "", uid: (Auth.auth().currentUser!.uid), imageRef: imgref!, date: Foundation.NSNumber())

    dateToSet = self.future.millisecondsSince1970

    refposts.setValue(m.toAnyObject(), withCompletionBlock: {(error,data) in
        self.m.key = data.key!
        self.m.image = self.ivImage.image
     self.m.date = self.dateToSet

        self.saveImage()
        self.saveToNSUserDefaualts(memory: self.m)


    })

}

// When clicking on the 'save' button: save the Memorey in the tableView and the database

@IBAction func saveMemorey(_ sender: UIButton) {

    let d = UserDefaults.standard

    if( mode == "newMemory")
    {
        self.addNewMemory()
        d.set(true, forKey: "userAdded")
    }

    else if mode == "edit"

    {
        self.editNewMemory()
        d.set(true, forKey: "userEdited")
    }

    d.synchronize()

    self.navigationController?.popViewController(animated: true) // Returns to the memories page after clicking 'save'



}

// Saving image in database function

func saveImage()
{
    let metaData = StorageMetadata()

    metaData.contentType = "image/png"

    let tempImageRef = sref.child(imgref!)
    let uploadData = ivImage.image!.pngData()
    tempImageRef.putData(uploadData!, metadata: metaData, completion: {(data,error) in
        if error == nil
        {
            print("upload success")

        }

        else

        {
            print("*upload not succeeded*")

        }

    })

}
// Saving to NSUserDefault (A class that provides simple storage of different data types solution.)

func saveToNSUserDefaualts(memory:Memory)

{

    let d : UserDefaults = UserDefaults.standard

    d.set(memory.title, forKey: "title")

    d.set(memory.body, forKey: "body")

    d.set(memory.key, forKey: "key")

    d.set(memory.imageRef, forKey: "imageRef")

    d.set(memory.uid, forKey: "uid")

    d.set(memory.key, forKey: "key")

    d.set(memory.date, forKey: "date")


let imageData = NSData(data:ivImage.image!.pngData()!)


    d.set(imageData, forKey: "imageData")

    d.synchronize()

}


override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Add MEmorey"
    ref = Database.database().reference()
    self.picker = UIImagePickerController()
    self.picker!.delegate = self

    //load data if its for edit

    if current != nil
    {
        txtTitle.text = current.title
        tBody.text = current.body
        ivImage.image = current.image


        func datePickerChanged(_ sender: UIDatePicker) {
            future = Date(milliseconds: Int (truncating: current.date))
            //Use midnight today as the starting date
            guard let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date()) else { return }

            //Calculate the number of days between today and the =user's chosen day.
            let difference = Calendar.current.dateComponents([.day], from: today, to: future)
            guard let days = difference.day else { return }
            let ess = days > 1 ? "s" : ""
            countLabel.text = "That date is \(days) day\(ess) away."
        }


        self.mode = "edit"
    }

    else
    {
        self.mode = "newMemory"
    }




    // Do any additional setup after loading the view.

    //Set up the date picker to pick dates, not dates & times
    datePicker.datePickerMode =  .date

    //Force the date picker to use midnight today as it's base date and
    //to pick a date at least 1 day in the future

    guard let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date()),
        let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: today)
        else {
            return
    }
    datePicker.minimumDate = tomorrow
    datePicker.date = tomorrow

}

// Tells the delegate that the user picked a still image or movie.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
    if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
    {
        ivImage.image = image
    }
    else
    {
        print("Something went wrong")

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

AddMemoryViewController

enter image description here

enter image description here

1 个答案:

答案 0 :(得分:0)

因此,您的应用程序失败,因为您试图将数据类型NSDate存储在Firebase中,但它不支持它。 here的更多内容。

  

Firebase只能存储NSNumberNSStringNSDictionaryNSArray类型的对象。

Set Firebase中的数据之前,您需要将日期转换为其中一种数据类型。

我建议通过NSNumber使用timeIntervalSince1970格式。自epoch起,您的时间将增加一倍。

您甚至可以使自己成为很好的扩展方法,以帮助您在DateDouble两种类型之间进行转换。

extension Date {
    var millisecondsSince1970: Int64 {
        return Int64((self.timeIntervalSince1970 * 1000.0).rounded()) 
    }

    init(milliseconds:Int) {
        self = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
    }
}

因此要在Firebase中设置值,您要做的就是使用下面的代码块。但是,当从Firebase获取值时,您需要执行类似的操作以将其转换回NSDate对象,以便在应用程序Date(milliseconds: data.date)中轻松使用。

let dateToSet = self.future.millisecondsSince1970

refposts.setValue(m.toAnyObject(), withCompletionBlock: {(error,data) in
        self.m.key = data.key!
        self.m.image = self.ivImage.image
        self.m.date = dateToSet

        self.saveImage()
        self.saveToNSUserDefaualts(memory: self.m)
})