ios – Issue Saving Image to Camera Roll in Swift


I am experimenting with using ContentMenu to allow users to do things such as saving images to their camera roll. Currently in the code, the value of the displayed image is of type Image so I made a function that’s supposed to convert it into a value of type UIImage and then the image would be saved to the camera roll via UIImageWriteToSavedPhotosAlbum(). The code works, however when I go to view the saved image in the camera roll it appears as an all-black image, rather than the actual image itself.

The code for the conversion is as follows:

extension Image {
    func asUIImage() -> UIImage? {
        // Create a UIView
        let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        
        // Create a hosting controller with the SwiftUI Image
        let hostingController = UIHostingController(rootView: self)
        
        // Assign the frame to the hosting controller
        hostingController.view.frame = uiView.bounds
        
        // Add the hosting controller's view to the UIView
        uiView.addSubview(hostingController.view)
        
        // Make the snapshot of the hosting controller's view
        UIGraphicsBeginImageContextWithOptions(uiView.bounds.size, uiView.isOpaque, 0.0)
        defer { UIGraphicsEndImageContext() }
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        uiView.layer.render(in: context)
        let uiImage = UIGraphicsGetImageFromCurrentImageContext()
        
        return uiImage
    }
}

which is called here:

func manyMediaView(media: [MediaOBJ]) -> some View {
        GeometryReader { geo in
            TabView {
                ForEach(media.indices, id: \.self) { index in
                    AsyncImage(url: media[index].link) { phase in
                        switch phase {
                        case .success(let image):
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fill)
                                .contentShape(Rectangle())
                                .onTapGesture {
                                    selectedImageIndex = index
                                    showFullImage = true
                                }
                                .contextMenu {
                                    Button(action: {
                                        // Action to copy the photo
                                    }) {
                                        Text("Copy Photo")
                                        Image(systemName: "doc.on.doc")
                                    }
                                    
                                    Button(action: {
                                        // Action to save the photo
                                        if let uiImage = image.asUIImage() {
                                            UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
                                            print("Saved successfully!")
                                        } else {
                                            print("Error: Unable to convert Image to UIImage.")
                                        }
                                    }) {
                                        Text("Save Photo")
                                        Image(systemName: "square.and.arrow.down")
                                    }
                                    
                                    ShareLink(item: viewModel.post.url) {
                                        Text("Share via ...")
                                        Image(systemName: "square.and.arrow.up")
                                    }
                                }
                        case .failure:
                            DefaultPlaceholder()
                                .maxHeight(600)
                                .onAppear {
                                    imageLoadKey = .init()
                                }
                        case .empty:
                            Color.clear
                        }
                    }
                    .tag(index)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                }
            }
            .cornerRadius(16)
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
            .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
            .gesture(
                DragGesture().onChanged { value in
                    if value.translation.width > 50 {
                        selectedImageIndex = max(selectedImageIndex - 1, 0)
                    } else if value.translation.width < -50 {
                        selectedImageIndex = min(selectedImageIndex + 1, media.count - 1)
                    }
                }
            )
            .fullScreenCover(isPresented: $showFullImage) {
                MultiImageGalleryView(imageUrls: media.map { $0.link }, isPresented: $showFullImage, selectedImageIndex: $selectedImageIndex)
            }
            .onTapGesture {
                // Intentionally empty to prevent auto navigation to SinglePostView
            }
        }
    }

What am I missing that’ll let the images be properly saved?

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img