UIHostingController获取view返回nil 生成表情包共享图片时崩溃
问题原因
- 你初始化
UIHostingController(rootView: Meme(...))之后,没有给这个hostingController的view设置有效frame,直接就调用createImage方法。此时view的frame是CGRect.zero,调用UIGraphicsBeginImageContextWithOptions传入宽高为0的尺寸,系统不会创建有效图形上下文,UIGraphicsGetCurrentContext()返回nil,你强制解包就触发崩溃。 - 额外隐患:你的Meme结构体里把image声明为
@State可选值,并且在body里直接用image!强制解包,如果传入的image为nil,也会触发强制解包崩溃;而且@State是用于视图内部状态管理的,你从外部传值进来不需要声明成@State,改成普通let或者@Binding才符合SwiftUI的数据流转规则。 - 你写的
createImage函数里多处用强制解包,只要任何一步出问题都会直接崩溃,没有容错处理。
修复方案
1. 修改按钮点击逻辑,给HostingController的view设置有效尺寸
Button( action: { items.removeAll() // 先创建Meme视图和HostingController let memeView = Meme(image: image, topText: $topText, bottomText: $bottomText) let hostingController = UIHostingController(rootView: memeView) // 手动设置有效frame,可根据你的实际需求调整高度 let targetSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 1.5) hostingController.view.frame = CGRect(origin: .zero, size: targetSize) // 强制触发布局,保证视图渲染完成 hostingController.view.layoutIfNeeded() // 再生成图像,避免强制解包崩溃 if let memeImage = createImage(from: hostingController.view) { items.append(memeImage) showingSharePage = true } } ) { Image(systemName: "square.and.arrow.up") .font(.title) }
2. 修复Meme结构体的错误声明,去掉强制解包
struct Meme: View { // 外部传入的固定参数用let,需要双向同步的文本用@Binding let image: Image? @Binding var topText: String @Binding var bottomText: String var body: some View { // 可选值判断,避免image为空时崩溃 if let image = image { image .resizable() .aspectRatio(contentMode: .fit) .frame(width: UIScreen.main.bounds.size.width) .overlay( TextField("TOP", text: $topText) .foregroundColor(.white) .font(Font.custom("HelveticaNeue-CondensedBlack", size: 30)) .frame(width: UIScreen.main.bounds.size.width * 0.75) .multilineTextAlignment(.center) .padding(.vertical, 50.0) .onTapGesture { topText = "" }, alignment: .top ) .overlay( TextField("BOTTOM", text: $bottomText) .foregroundColor(.white) .font(Font.custom("HelveticaNeue-CondensedBlack", size: 30)) .frame(width: UIScreen.main.bounds.size.width * 0.75) .multilineTextAlignment(.center) .padding(.vertical, 50.0) .onTapGesture { bottomText = "" }, alignment: .bottom ) } else { // 空数据占位视图,避免渲染异常 Color.gray .frame(width: UIScreen.main.bounds.size.width, height: 300) } } }
3. 优化createImage函数,增加容错处理
func createImage(from view: UIView) -> UIImage? { // 先判断尺寸是否有效 guard view.frame.size.width > 0, view.frame.size.height > 0 else { return nil } // 用屏幕scale保证生成的图像清晰度 UIGraphicsBeginImageContextWithOptions(view.frame.size, true, UIScreen.main.scale) // 保证方法退出时一定会释放上下文 defer { UIGraphicsEndImageContext() } guard let context = UIGraphicsGetCurrentContext() else { return nil } view.layer.render(in: context) return UIGraphicsGetImageFromCurrentImageContext() }
内容的提问来源于stack exchange,提问作者mathusan.selvakumar
相关产品推荐
相关产品推荐

