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

如何使用带代理的UIImagePickerController?子视图类获取图片返回问题

解决UIView子类获取ViewController图片选择结果的方案

我来帮你搞定这个问题!你之前用代理出各种错误,大概率是协议定义、代理属性设置或者代理赋值环节踩坑了——比如没给代理加weak导致循环引用、忘记设置aView.delegate = self,或者协议没声明为类专属。下面给你两种靠谱的实现方式,按需选择:

方案一:正确实现代理模式

这种方式适合需要多个回调的场景,扩展性更强。

第一步:在A类中定义代理协议

import UIKit

// 定义类专属协议,保证代理可以用weak修饰
protocol AViewDelegate: AnyObject {
    // 通知ViewController需要触发图片选择器
    func aViewDidRequestImage(_ view: AView)
}

class AView: UIView {
    // 用weak修饰代理,避免循环引用
    weak var delegate: AViewDelegate?
    
    // 假设这是你触发选图的按钮点击事件
    @IBAction func chooseImageBtnTapped(_ sender: UIButton) {
        // 通知代理发起图片选择请求
        delegate?.aViewDidRequestImage(self)
    }
    
    // 供ViewController调用,用来接收并显示图片
    func updateImageView(with image: UIImage?) {
        // 这里把图片赋值给A类里的UIImageView
        // self.imageView.image = image
    }
}

第二步:在ViewController中实现代理

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AViewDelegate {
    
    var aView: AView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 从xib加载A类实例并添加到视图
        let nib = UINib(nibName: "AView", bundle: nil)
        aView = nib.instantiate(withOwner: nil, options: nil).first as! AView
        aView.frame = CGRect(x: 50, y: 100, width: 300, height: 300)
        
        // 关键!给AView设置代理,否则代理方法不会执行
        aView.delegate = self
        
        view.addSubview(aView)
    }
    
    // MARK: - AViewDelegate 实现
    func aViewDidRequestImage(_ view: AView) {
        // 弹出图片选择器
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary // 可以改成.camera
        present(imagePicker, animated: true)
    }
    
    // MARK: - UIImagePickerControllerDelegate 实现
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true)
        
        // 获取选中的原图
        let selectedImage = info[.originalImage] as? UIImage
        
        // 直接调用A类的方法把图片传回去
        aView.updateImageView(with: selectedImage)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
    }
}

代理模式避坑指南

  • 协议必须继承AnyObject(或者加@objc),这样代理属性才能用weak修饰,避免循环引用导致内存泄漏和回调无响应。
  • 一定要记得设置aView.delegate = self,这是最容易忘的点,没设置的话代理方法根本不会触发。
  • 代理方法调用时加?,避免代理为nil时崩溃。

方案二:更简洁的闭包回调

如果只是单一的选图回调,闭包写法会更简洁,不用写协议。

第一步:在A类中定义闭包属性

import UIKit

class AView: UIView {
    // 定义闭包,用来通知ViewController触发选图
    var onRequestImage: (() -> Void)?
    
    // 供ViewController调用的图片更新方法
    func updateImageView(with image: UIImage?) {
        // 处理图片显示逻辑
        // self.imageView.image = image
    }
    
    @IBAction func chooseImageBtnTapped(_ sender: UIButton) {
        // 调用闭包通知外部
        onRequestImage?()
    }
}

第二步:在ViewController中绑定闭包

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    var aView: AView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let nib = UINib(nibName: "AView", bundle: nil)
        aView = nib.instantiate(withOwner: nil, options: nil).first as! AView
        aView.frame = CGRect(x: 50, y: 100, width: 300, height: 300)
        
        // 绑定闭包,注意用[weak self]避免循环引用
        aView.onRequestImage = { [weak self] in
            guard let self = self else { return }
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = .photoLibrary
            self.present(imagePicker, animated: true)
        }
        
        view.addSubview(aView)
    }
    
    // MARK: - UIImagePickerControllerDelegate
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true)
        let selectedImage = info[.originalImage] as? UIImage
        aView.updateImageView(with: selectedImage)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
    }
}

闭包模式注意点

  • 闭包中一定要用[weak self],否则AView持有闭包,闭包持有ViewController,会造成循环引用,内存无法释放。
  • 调用闭包时加?,防止闭包未赋值导致崩溃。

内容的提问来源于stack exchange,提问作者Scott

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:12:30