集成UISearchController后出现+[CATransaction synchronize]事务内调用报错
我之前也踩过这个坑!这个报错本质是UIKit在处理UISearchController的UI更新时,不小心在未完成的CATransaction事务周期内触发了同步操作,大多是因为属性设置顺序不对或者上下文配置不明确导致的。下面是几个亲测有效的解决方案:
1. 调整属性配置顺序,明确上下文归属
你的代码里可能存在两个小问题:一是definesPresentationContext = true没有明确指定是当前ViewController的属性(应该用self.definesPresentationContext),二是属性设置和赋值给navigationItem的顺序不合理。试试按这个顺序重构代码:
override func viewDidLoad() { super.viewDidLoad() // 1. 初始化搜索控制器 let searchController = UISearchController(searchResultsController: nil) // 2. 配置搜索控制器核心属性 searchController.obscuresBackgroundDuringPresentation = false searchController.searchResultsUpdater = self searchController.searchBar.placeholder = NSLocalizedString("Search", comment: "") // 3. 明确设置当前控制器的展示上下文(这一步很关键) self.definesPresentationContext = true // 4. 配置搜索栏样式 searchController.searchBar.barTintColor = UIColor.groupTableViewBackground // 5. 最后再将搜索控制器赋值给navigationItem navigationItem.searchController = searchController // 如果需要隐藏导航栏,可以延迟设置这个属性 DispatchQueue.main.async { searchController.hidesNavigationBarDuringPresentation = true } }
2. 延迟设置hidesNavigationBarDuringPresentation
hidesNavigationBarDuringPresentation = true这个属性很容易触发事务冲突,因为它会在搜索框激活时触发导航栏的动画更新。如果直接在viewDidLoad里设置,可能会和navigationItem的初始化事务重叠。用DispatchQueue.main.async包裹可以让这个操作在当前事务完成后再执行,避免冲突。
3. 检查上层容器的上下文设置
如果你的ViewController是嵌入在UINavigationController或UITabBarController中,确保上层容器的definesPresentationContext没有被错误设置为false。不过通常只要当前ViewController设置为true就足够了。
4. 避免在事务中执行额外UI操作
如果你的viewDidLoad或viewWillAppear里还有其他动画、布局更新操作,尽量把它们和搜索控制器的配置分开执行,比如用异步队列延迟,或者放在viewDidAppear里执行(viewDidAppear时UI事务已经完成)。
按照上面的方法调整后,这个CATransaction的报错应该就能消失了。
内容的提问来源于stack exchange,提问作者Rafaela Lourenço

