Segue传值时出现_UIPerformResizeOfTextViewForTextContainer断言失败及trimVideo函数咨询
关于Segue传值时「Assertion failure in void _UIPerformResizeOfTextViewForTextContainer」断言失败的解决办法
这个断言问题基本都和UITextView的布局逻辑冲突有关,我整理了几个常见的排查和解决方向:
- 检查TextView的约束完整性:Segue跳转后目标控制器的TextView如果约束不清晰(比如只给了上下约束但没给宽度,或者约束冲突),布局系统在计算尺寸时就会触发断言。你可以打开Xcode的「Debug View Hierarchy」查看约束警告,确保TextView有明确的top/leading/trailing/bottom约束,或者固定宽度+高度(根据需求选择)。
- 延迟给TextView赋值:如果在
viewDidLoad里直接给TextView塞大量文本,此时视图还没完成布局,系统计算contentSize时容易出问题。可以把赋值操作挪到viewDidAppear(_:)里,或者用DispatchQueue.main.async包裹,让布局先完成再更新内容:DispatchQueue.main.async { self.textView.text = passedData } - 避免手动修改contentSize:如果你手动设置过TextView的
contentSize或者强制修改scrollEnabled,可能会干扰系统的自动布局逻辑。尽量让系统自己管理这些属性,除非有特别明确的需求,否则别随便改。 - 规范Segue传值时机:在
prepare(for:sender:)里,只把数据存到目标控制器的属性里,不要直接操作目标控制器的TextView(比如直接赋值)。等目标控制器的视图生命周期走到合适阶段(比如viewWillAppear),再把属性里的数据赋值给TextView。
视频裁剪函数
trimVideo的技术指导与完善 你给出的代码只是开头部分,我来帮你补全核心逻辑并给出优化建议:
1. 补全核心裁剪流程
首先需要完成轨道添加、时间范围设置和导出会话的配置,完整的函数逻辑大概是这样:
// 先定义TrimPoints结构体(假设你还没定义) struct TrimPoints { let start: Double // 开始时间(秒) let end: Double // 结束时间(秒) } func trimVideo(sourceURL: URL, destinationURL: URL, trimPoints: TrimPoints, completion: @escaping () -> Void) { guard sourceURL.isFileURL else { print("源URL不是文件URL") return } guard destinationURL.isFileURL else { print("目标URL不是文件URL") return } // 配置Asset,开启精确时间计算 let options = [AVURLAssetPreferPreciseDurationAndTimingKey: true] let asset = AVURLAsset(url: sourceURL, options: options) let preferredPreset = AVAssetExportPresetPassthrough // 验证预设是否支持当前资产 guard verifyPresetForAsset(preset: preferredPreset, asset: asset) else { print("当前预设不支持该资产") return } // 创建Composition和轨道 let composition = AVMutableComposition() guard let videoTrack = asset.tracks(withMediaType: .video).first else { print("找不到视频轨道") return } guard let audioTrack = asset.tracks(withMediaType: .audio).first else { print("找不到音频轨道") return } guard let videoCompositionTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid), let audioCompositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else { print("创建Composition轨道失败") return } // 设置裁剪时间范围 let timescale = CMTimeScale(600) // 用600可以保证时间精度 let startTime = CMTimeMakeWithSeconds(trimPoints.start, preferredTimescale: timescale) let endTime = CMTimeMakeWithSeconds(trimPoints.end, preferredTimescale: timescale) let timeRange = CMTimeRangeFromTimeToTime(startTime, endTime) // 插入时间范围到Composition轨道 do { try videoCompositionTrack.insertTimeRange(timeRange, of: videoTrack, at: .zero) try audioCompositionTrack.insertTimeRange(timeRange, of: audioTrack, at: .zero) } catch { print("插入时间范围失败:\(error.localizedDescription)") return } // 处理目标文件覆盖问题 do { if FileManager.default.fileExists(atPath: destinationURL.path) { try FileManager.default.removeItem(at: destinationURL) } } catch { print("删除旧文件失败:\(error.localizedDescription)") return } // 配置导出会话并开始导出 guard let exportSession = AVAssetExportSession(asset: composition, presetName: preferredPreset) else { print("创建导出会话失败") return } exportSession.outputURL = destinationURL exportSession.outputFileType = .mp4 // 根据需求修改格式,比如.mov exportSession.timeRange = timeRange exportSession.exportAsynchronously { switch exportSession.status { case .completed: DispatchQueue.main.async { completion() } case .failed: print("导出失败:\(exportSession.error?.localizedDescription ?? "未知错误")") case .cancelled: print("导出被取消") default: break } } } // 实现verifyPresetForAsset辅助函数 func verifyPresetForAsset(preset: String, asset: AVAsset) -> Bool { guard AVAssetExportSession.allExportPresets().contains(preset) else { return false } return AVAssetExportSession(asset: asset, presetName: preset) != nil }
2. 关键优化点
- 时间精度:使用
AVURLAssetPreferPreciseDurationAndTimingKey: true可以让Asset更精确地计算时间,避免裁剪出现偏差。 - 错误处理:添加了轨道检查、文件删除、导出状态判断等错误处理,避免程序崩溃或静默失败。
- 线程安全:导出完成后的
completion回调切回了主线程,方便你后续更新UI(比如显示成功提示)。 - 文件覆盖:导出前先删除目标路径的旧文件,否则导出会话会直接失败。
内容的提问来源于stack exchange,提问作者BigBoy1337
相关产品推荐
相关产品推荐

