You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift开发:如何保存选中图片并传递至TableView所在的主ViewController

Hey there! Welcome to Stack Overflow—super glad you’re finding the platform helpful for your dev questions, and awesome to hear your Swift project is moving along smoothly. Let’s figure out how to get that selected image from your second view controller over to the main one, plus cover saving if you need it.

First off, using a constant.swift file for data transfer works for simple text, but it’s not ideal for images (they’re larger objects and global storage can lead to memory bloat or unexpected state). Let’s go with cleaner, more scalable approaches:

方案1:闭包(Closure)传递数据(推荐,轻量灵活)

This is my go-to for simple reverse data flow because it’s compact and doesn’t require extra protocol setup.

Step 1: Set up the closure in your second ViewController

Add a closure property to capture the submitted title and image, then trigger it when the user taps "done":

class SecondViewController: UIViewController {
    @IBOutlet weak var titleTextField: UITextField!
    @IBOutlet weak var selectedImageView: UIImageView! // Assume you have this to preview the image
    private var pickedImage: UIImage?
    
    // Define the closure to pass data back
    var onSubmit: ((String, UIImage?) -> Void)?

    // Handle image picker selection (you likely already have this)
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        pickedImage = info[.originalImage] as? UIImage
        selectedImageView.image = pickedImage
        picker.dismiss(animated: true)
    }

    // Triggered when user taps "done" to submit
    @IBAction func doneButtonTapped(_ sender: UIButton) {
        guard let title = titleTextField.text, !title.trimmingCharacters(in: .whitespaces).isEmpty else {
            // Show an alert if title is empty (optional but user-friendly)
            let alert = UIAlertController(title: "Oops", message: "Please enter a title", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true)
            return
        }
        
        // Pass data back via closure
        onSubmit?(title, pickedImage)
        dismiss(animated: true)
    }
}

Step 2: Hook up the closure in your main ViewController

When you present the second VC, assign the closure to handle the incoming data and refresh your table view:

class MainViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    // Store your items (title + image) here
    private var items: [(title: String, image: UIImage?)] = []

    @IBAction func addButtonTapped(_ sender: UIButton) {
        guard let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {
            return
        }
        
        // Set up the closure to receive data
        secondVC.onSubmit = { [weak self] title, image in
            guard let self = self else { return }
            // Add the new item to your array
            self.items.append((title: title, image: image))
            // Refresh the table view to show the new item
            self.tableView.reloadData()
        }
        
        present(secondVC, animated: true)
    }

    // MARK: - UITableView DataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell // Use your custom cell class
        let item = items[indexPath.row]
        cell.titleLabel.text = item.title
        cell.itemImageView.image = item.image
        return cell
    }
}
方案2:代理模式(Delegate Pattern)

If you’re working on a larger project where you might need more complex communication between VCs, delegates are a classic, scalable choice.

Step 1: Define a delegate protocol

Add this outside your second VC class:

protocol SecondViewControllerDelegate: AnyObject {
    func didSubmitItem(title: String, image: UIImage?)
}

Step 2: Add a delegate property to your second VC

class SecondViewController: UIViewController {
    weak var delegate: SecondViewControllerDelegate?
    // ... (keep your existing image picker and title text field code)

    @IBAction func doneButtonTapped(_ sender: UIButton) {
        guard let title = titleTextField.text, !title.trimmingCharacters(in: .whitespaces).isEmpty else {
            // Show alert as before
            return
        }
        
        // Call the delegate method to pass data back
        delegate?.didSubmitItem(title: title, image: pickedImage)
        dismiss(animated: true)
    }
}

Step 3: Conform to the delegate in your main VC

class MainViewController: UIViewController, UITableViewDataSource, SecondViewControllerDelegate {
    // ... (keep your items array and table view code)

    @IBAction func addButtonTapped(_ sender: UIButton) {
        guard let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {
            return
        }
        secondVC.delegate = self
        present(secondVC, animated: true)
    }

    // Implement the delegate method
    func didSubmitItem(title: String, image: UIImage?) {
        items.append((title: title, image: image))
        tableView.reloadData()
    }
}
额外:持久化保存图片(如果需要)

If you want to keep images even after the app closes, save them to the app’s document directory instead of just keeping them in memory:

Save the image to disk

func saveImageToDisk(_ image: UIImage) -> URL? {
    guard let imageData = image.pngData() else { return nil } // Use jpegData(compressionQuality: 0.8) for smaller files
    let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let imageFileName = UUID().uuidString + ".png" // Unique name to avoid overwrites
    let imageURL = documentsDir.appendingPathComponent(imageFileName)
    
    do {
        try imageData.write(to: imageURL)
        return imageURL
    } catch {
        print("Failed to save image: \(error.localizedDescription)")
        return nil
    }
}

Load the image from disk later

func loadImageFromDisk(url: URL) -> UIImage? {
    do {
        let imageData = try Data(contentsOf: url)
        return UIImage(data: imageData)
    } catch {
        print("Failed to load image: \(error.localizedDescription)")
        return nil
    }
}

Instead of passing the UIImage directly, you’d pass the saved URL, then load it when displaying in the table view cell. This is better for memory if you have lots of images.


内容的提问来源于stack exchange,提问作者Nick Eßer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:19:27