【问题标题】:Attempting to load the view of a view controller while it is deallocating... UISearchController尝试在解除分配时加载视图控制器的视图... UISearchController
【发布时间】:2026-01-08 08:25:03
【问题描述】:

我有创建UISearchController' in my UIVIew'sviewDidLoad`的代码。

 self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.searchBar.delegate = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()
        controller.hidesNavigationBarDuringPresentation = false //prevent search bar from moving
        controller.searchBar.placeholder = "Search for song"

        self.myTableView.tableHeaderView = controller.searchBar

        return controller

    })()

在此关闭完成后,控制台中会立即出现此警告:

Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UISearchController: 0x154d39700>)

我不明白我做错了什么。 This similar question 并不是我的实际情况(至少我不这么认为)。怎么回事?

【问题讨论】:

  • xkcd.com/583 如果我把它扔到我的表 VC viewDidLoad() 中就可以了。建议 a) 包括完整的 VC 源代码清单和 b) 确保错误确实发生在您认为的时间和地点。
  • 另外,做更多的研究,例如:*.com/questions/31006045/… 有同样的错误
  • 所以,我做了一个 swift 项目,一切都以编程方式完成,没有故事板,我没有问题,这是故事板的问题,也许,我不知道,但我假设你正在使用故事板,对吗?当我以编程方式说时,我的意思是没有笔尖,没有情节提要,所有代码都可以正常工作
  • @BaseZen 我在})() 之前和})() 之后设置了一个断点。闭包结束后抛出错误。我有一个UIViewController,而不是tableViewController
  • @Larcerax 我确实有一个故事板。它只包含一个 Navigation Controller 和一个 UIViewController(它们是相连的。)

标签: ios swift uisearchcontroller


【解决方案1】:

UISearchController 的视图必须在释放前从其父视图中移除。 (猜这是一个错误)

Objective-C...

-(void)dealloc { 
    [searchController.view removeFromSuperview]; // It works!
}

斯威夫特 3...

deinit {
    self.searchController.view.removeFromSuperview()
}

我在这个问题上苦苦挣扎了几个星期。 ^^

【讨论】:

  • 这真的很奇怪......但它也对我有用。我想这确实是一个错误。
  • 我在-viewDidLoad 中分配的UISearchControler 遇到了同样的问题。这绝对是一个错误 - 如果 UISearchController 在其视图加载之前被释放,则会出现此警告。如果我点击搜索字段(从而加载视图),它不会出现。所以在我的dealloc 中,我调用[self.searchController loadViewIfNeeded](iOS 9 中的新功能),
  • @Leehro 的评论是我的答案。结果是if #available(iOS 9.0, *) { self.searchController?.loadViewIfNeeded() }
  • 我会在@Leehro 的评论中补充说,在 dealloc 中不需要这样做,您可以在 viewDidLoad 中执行 loadViewIfNeeded。
  • 感谢@Leehro 和@Clafou...添加调用[self.searchController loadViewIfNeeded]; (Obj-C) 是解决我代码中问题的答案。
【解决方案2】:

解决了!这是一个简单的修复。我更改了此代码

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

对此:

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

这解决了问题。

【讨论】:

  • 我把它改成了你的意思。 :-) 无论如何,这就是为什么在问题中包含整个来源会更好,但最好是自己找到它;-)
  • 我也遇到了这个烦人的警告,按照您的回答,我修复了所有问题。但我不知道为什么!需要而不是分配一个新的 UISearchController...你能解释一下吗?
  • 不确定,我也想解释一下。
  • 如果我从 var resultSearchController = UISearchController() 更改为 var resultSearchController: UISearchController!我收到致命错误:在 noOfRowInSection 中展开可选值时意外发现 nil。我有大量数组,这会产生错误吗?建议我。
  • 我发现,我没有从storyboard做委托和数据源,而是写在代码中,问题就解决了。
【解决方案3】:

这是对我有用的 Swift 版本(类似于 JJH 的回答):

deinit{
    if let superView = resultSearchController.view.superview
    {
        superView.removeFromSuperview()
    }
}

【讨论】:

  • @alex 我把它放在初始化 resultSearchController 的视图控制器的末尾。
  • 你真的不需要if let,因为如果superview == nil.removeFromSuperView()不会做任何事情
【解决方案4】:
class SampleClass: UITableViewController, UISearchBarDelegate {

private let searchController =  UISearchController(searchResultsController: nil)

 override func viewDidLoad() {
        super.viewDidLoad()

        searchController.loadViewIfNeeded() // Add this line before accessing searchController
 }

}

【讨论】:

    【解决方案5】:

    在完全设置 UISearchController 之前,我设法通过向 viewDidLoad 添加行来让我的解决方案一起工作:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.rightBarButtonItem = self.editButtonItem()
    
        if #available(iOS 9.0, *) {
            self.resultSearchController.loadViewIfNeeded()// iOS 9
        } else {
            // Fallback on earlier versions
            let _ = self.resultSearchController.view          // iOS 8
        }
        self.resultSearchController = ({
            let controller = UISearchController(searchResultsController: nil)
            controller.searchResultsUpdater = self
            controller.dimsBackgroundDuringPresentation = false
            controller.searchBar.sizeToFit()
    
            self.tableView.tableHeaderView = controller.searchBar
    
            return controller
        })()
    
        self.tableView.reloadData()
    
    }
    

    【讨论】:

    • 我也尝试了这里给出的所有其他解决方案,但没有一个确实抑制了警告(尽管搜索控制器确实在运行时工作);这做到了。谢谢!
    • 这对我也有帮助,但我必须在 初始化 UISearchController 之后添加该行。 self.searchController = ({ let controller = UISearchController(searchResultsController: nil) controller.searchResultsUpdater = self controller.dimsBackgroundDuringPresentation = false controller.searchBar.delegate = self definesPresentationContext = true controller.searchBar.sizeToFit() return controller })() 然后self.searchController.loadViewIfNeeded()
    • 为什么我们需要在块中初始化?
    【解决方案6】:

    在 Swift2 中,由于一个明显的错误,我收到了相同的错误消息:

    let alertController = UIAlertController(title: "Oops",
        message:"bla.", preferredStyle: UIAlertControllerStyle.Alert)
    
    alertController.addAction(UIAlertAction(title: "Ok", 
         style: UIAlertActionStyle.Default,handler: nil))
    
    self.presentViewController(alertController, animated: true, completion: nil)
    

    由于我自己的一个愚蠢的复制错误,我没有包含 self.presentViewController 行。这导致了同样的错误。

    【讨论】:

      【解决方案7】:

      在适合我的 Swift 2.2 版本中

      deinit {
          self.searchController?.view.removeFromSuperview()
      }
      

      我觉得很有帮助!

      【讨论】:

        【解决方案8】:

        这不是错误。似乎您必须避免在不展示它们的情况下创建 ViewController。所以在SomeViewController()let variable: SomeViewController 之后,你必须调用类似self.presentViewController(yourViewController ...etc) 的东西。如果你不这样做,当这个视图控制器被释放时你会得到这个警告。

        【讨论】:

          【解决方案9】:

          我的工作是这样的

          func initSearchControl(){
          
                  searchController = UISearchController(searchResultsController: nil)
          
                  if #available(iOS 9.0, *) {
                      searchController.loadViewIfNeeded()
                  } else {
                      let _ = self.searchController.view
                  }
          
                  searchController.searchResultsUpdater = self
                  searchController.dimsBackgroundDuringPresentation = false
                  definesPresentationContext = true
                  tableView.tableHeaderView = searchController.searchBar
                  searchController.searchBar.sizeToFit()
              }
          

          searchController.loadViewIfNeeded() 解决了这个问题,但是你需要在初始化searchController之后调用它

          【讨论】:

            【解决方案10】:

            viewDidLoad() 中创建搜索控制器并将其搜索栏设置为导航项的标题视图不会创建对搜索控制器的强引用,这就是它被释放的原因。

            所以不要这样做:

            override func viewDidLoad() {
                super.viewDidLoad()
                // Create search controller
                let searchController = UISearchController(searchResultsController: nil)
                // Add search bar to navigation bar
                navigationItem.titleView = searchController.searchBar
                // Size search bar
                searchController.searchBar.sizeToFit()
            }
            

            你应该这样做:

            var searchController: UISearchController!
            
            override func viewDidLoad() {
                super.viewDidLoad()
                // Create search controller
                searchController = UISearchController(searchResultsController: nil)
                // Add search bar to navigation bar
                navigationItem.titleView = searchController.searchBar
                // Size search bar
                searchController.searchBar.sizeToFit()
            }
            

            【讨论】:

              【解决方案11】:

              我使用了 Derek 的答案,但不得不稍微改变一下。 为我提供的答案崩溃了,因为对 loadViewIfNeeded() 的调用发生在定义 resultSearchController 之前。 (我的声明是

              var resultSearchController: UISearchController!
              

              )。所以我只是在之后移动它并且它起作用了。

              如果我完全忽略了通话,错误仍然存​​在,所以我确信它是答案的重要组成部分。我无法在 iOS 8 上对其进行测试。

              【讨论】:

                【解决方案12】:

                似乎视图是延迟加载的,如果您分配了控制器并且从不显示它,则视图没有加载。在这种情况下,如果控制器被解除分配,您将收到此警告。你可以显示一次,或者调用它的 loadViewIfNeed() 方法,或者使用 'let _ = controller.view' 来强制加载视图以避免这个警告。

                【讨论】:

                • 在 iOS 8 上,你只能使用 'let _ = controller.view'。
                【解决方案13】:

                我参加聚会有点晚了,但这是我的解决方案:

                var resultSearchController: UISearchController!
                
                override func viewDidLoad()
                {
                    super.viewDidLoad()
                
                    self.resultSearchController = ({
                        let searchController = UISearchController(searchResultsController: nil)
                        searchController.searchResultsUpdater = self
                        searchController.dimsBackgroundDuringPresentation = false
                        searchController.searchBar.sizeToFit()
                        return searchController
                    })()
                
                    self.tableView.tableHeaderView = self.resultSearchController.searchBar
                    self.tableView.reloadData()
                }
                

                我希望它对你有用。

                【讨论】:

                • 这与直接初始化和设置有何不同;我的意思是不使用块语法?
                最近更新 更多