简体   繁体   中英

Image is saved in an unknown format to the Firebase

Im tryna to upload some data and Picked Image to Storage , but its uploads like unknown format to Storage . Everything else is fine with the rest of the data.

This is Add Item View , I have form with text fields title, description and author, then I tapped on button "Done" its saves to collection "Items" in Firebase database, but it doesn't save Picked Images , its only saves like "unknown type" to Storage. What I missed?

I cleaned the code as much as possible and left only the relevant lines of code for easier reading.

IMAGE 3 : 在此处输入图像描述

struct AddItemView: View {
    
    
    @Environment(\.presentationMode) private var presentationMode
    @State var presentActionSheet = false
    @State var showPicker: Bool = false
    @State var pickedImages: [UIImage] = []
    @State var picData : Data = .init(count: 0)
    @State var image : UIImage?
    
    // MARK: - State (Initialiser-modifiable)
    
    @ObservedObject var viewModel = NewItemView()
    var mode: Mode = .new
    var completionHandler: ((Result<Action, Error>) -> Void)?
    
    // MARK: - UI Components
    
    var saveButton: some View {
        Button(action: {
            self.handleDoneTapped() // - look at the end of the code 
            
        }) {
            
            Text(mode == .new ? "Done" : "Save")
        }
        .disabled(!viewModel.modified)
    }
    
    
    
    var body: some View {
        NavigationView {
            Group {
                Section(header: Text("New Item")) {
                    TextField("Title", text: $viewModel.singleitem.title)
                    TextField("Description", text: $viewModel.singleitem.description)
                }
                
                Section(header: Text("Author")) {
                    TextField("Author", text: $viewModel.singleitem.author)
                }
                
                if mode == .edit {
                    Section {
                        Button("Delete item") { self.presentActionSheet.toggle() }
                            .foregroundColor(.red)
                    }
                }
                
                Button {
                    
                    showPicker.toggle()
                    
                } label: {
                    
                    Image(systemName: "plus")
                    
                }
                
                TabView {
                    ForEach(pickedImages, id: \.self) { image in
                        
                        GeometryReader { proxy in
                            
                            let size = proxy.size
                            Image(uiImage: image)
                            
                        }
                        .padding()
                    }
                }
                .frame(height: 450)
                //.tabViewStyle(.page(indexDisplayMode: pickedImages.isEmpty ? .never : .always))
            }
            .navigationBarItems(leading: cancelButton, trailing: saveButton)
            
        }
        .popupImagePicker(show: $showPicker) { assets in
            // MARK: Example
            let manager = PHCachingImageManager.default()
            let options = PHImageRequestOptions()
            options.isSynchronous = true
            DispatchQueue.global(qos: .userInteractive).async {
                assets.forEach { asset in
                    manager.requestImage(for: asset, targetSize: .init(), contentMode: .default, options: options) { image, _ in
                        guard let image = image else { return }
                        DispatchQueue.main.async {
                            self.pickedImages.append(image)
                            
                        }
                        
                    }
                    
                }
            }
            
        }
        
        // MARK: Grid Image Content
        
        
        .navigationTitle(mode == .new ? "Item" : viewModel.singleitem.title)
        .navigationBarTitleDisplayMode(mode == .new ? .inline : .large)
        .navigationBarItems(
            leading: cancelButton,
            trailing: saveButton
        )
        .actionSheet(isPresented: $presentActionSheet) {
            ActionSheet(title: Text("Are you sure?"),
                        buttons: [
                            .destructive(Text("Delete item"),
                                         action: { self.handleDeleteTapped() }),
                            .cancel()
                        ])
        }
        
        
        
    }
    
    // MARK: - Action Handlers

    
    func handleDoneTapped() {   // then I press Done it should save all data from the View to database and Storage.
        self.viewModel.handleDoneTapped()
        self.uploadImage()     // This function below (to upload image to storage)
        self.dismiss()
    }
    
    func uploadImage() {      // Not saves images from Picked Images, just unknown files.
        
        let storage = Storage.storage().reference()
        let userId = Auth.auth().currentUser?.uid
        storage.child("itemImages").child(userId ?? "").putData(self.picData, metadata: nil) {
            
            (_, err) in
            if err != nil {
                
                print((err?.localizedDescription)!)
                return
                
            }
            
            storage.child("itemImages").child(userId ?? "").downloadURL {(url, err) in
                
                if err != nil {
                    
                    print((err?.localizedDescription)!)
                    return
                }
                
            }
        }
        
    }

}

Also I have New Item Class with all function to save it into database:

class NewItemView: ObservableObject {
  // MARK: - Public properties
  
  @Published var singleitem: SingleItem 
  @Published var modified = false
  
  // MARK: - Internal properties
  
  private var cancellables = Set<AnyCancellable>()
  
  // MARK: - Constructors
  
    init(singleitem: SingleItem = SingleItem(title: "", author: "", description: "", image: "")) {
    self.singleitem = singleitem
    
      self.$singleitem
      .dropFirst()
      .sink { [weak self] singleitem in
        self?.modified = true
      }
      .store(in: &self.cancellables)
  }
  
  // MARK: - Firestore

  private var db = Firestore.firestore()
  
  private func addItem(_ singleitem: SingleItem) {
    do {
        var addedItem = singleitem
        addedItem.userId = Auth.auth().currentUser?.uid
        _ = try db.collection("items").addDocument(from: addedItem)
    }
    catch {
      print(error)
    }
      
      
  }

and SingleItem with all var's:

struct SingleItem: Identifiable, Codable {
  @DocumentID var id: String?
    var title : String
    var author : String
    var description : String
    @ServerTimestamp var createdTime: Timestamp?
    var userId : String?
    var image : String
}
  
  enum CodingKeys: String, CodingKey {
    case id
    case title
    case author
    case description = ""
    case image
  }

In view of your new code/picture. The error tells you that in func uploadImage() , you are assigning a binding array of pickedImages: [UIImage] to a single picData .

Use let picData: Data = pickedImages[0].jpegData(compressionQuality: 1) , no $ , and change [0] to whatever image index you want. You will have to check that this index exist, otherwise you will get an out of index error.

Note this let picData.. . in func uploadImage() is completely different to the @State var picData... you declare in AddItemView .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM