Home > Net >  Image is saved in an unknown format to the Firebase
Image is saved in an unknown format to the Firebase

Time:10-11

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: enter image description here

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
  }

CodePudding user response:

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.

  • Related