尝试在取消分配时加载视图控制器的视图…UISearchController


80

我有创建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>)

我不明白我在做什么错。类似的问题并不是我的实际情况(至少我不这么认为)。到底是怎么回事?


xkcd.com/583如果我将其放入Table VC中,则可以正常工作viewDidLoad()。建议a)包括整个VC源清单,以及b)确保错误确实在您认为发生的时间和地点发生。
2015年

另外,请进行更多研究,例如:stackoverflow.com/questions/31006045/…具有相同的错误
BaseZen 2015年

所以,我做了一个迅速的项目,按程序进行了所有工作,没有情节提要,也没有问题,这是否是您遇到的情节提要的问题,也许我不知道,但是我认为您正在使用情节提要,对吗?当我以编程方式说时,我的意思是没有笔尖,没有故事板,所有代码都可以正常工作
Loxx

@BaseZen我之前设置了断点 })()和之后})()。关闭结束后,将引发错误。我有一个UIViewController,而不是一个tableViewController
MortalMan 2015年

@ Larcerax我确实有一个情节提要。它仅包含导航控制器和一个UIViewController(它们连接。)
MortalMan

Answers:


118

在取消分配之前,必须将UISearchController的视图从其超级视图中删除。(猜测这是一个错误)

物镜

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

斯威夫特3 ...

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

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


1
这真的很奇怪...但这也对我有用。我想这确实是一个错误。
Mihai Fratu 2015年

22
我在UISearchControler分配时遇到了同样的问题-viewDidLoad。绝对是一个错误-如果在UISearchController加载视图之前将其释放,则会出现此警告。如果我点击搜索字段(从而加载视图),则不会出现。因此dealloc,我打电话给[self.searchController loadViewIfNeeded](iOS 9中的新功能),
Leehro 2015年

4
@Leehro的评论对我来说是答案。出来的时间是if #available(iOS 9.0, *) { self.searchController?.loadViewIfNeeded() }
蒂姆(Tim)

6
我要添加到@Leehro的注释中,无需在dealloc中执行此操作,而可以在viewDidLoad中执行loadViewIfNeeded。
Clafou

感谢@Leehro和@Clafou ...添加调用[self.searchController loadViewIfNeeded];(Obj-C)是解决我代码中问题的答案。
andrewbuilder

36

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

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

对此:

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

这样可以解决问题。


1
我将其更改为您的意思。:-)无论如何,这就是为什么在问题中包含整个源会更好,但是最好自己找到它;-)
BaseZen 2015年

我也收到了这个令人讨厌的警告,并且按照您的回答,我修复了所有问题。但是我不知道为什么!需要而不是分配新的UISearchController ...您是否会责怪我?
射手座

不确定,我也想要一个解释。
MortalMan 2015年

如果我从var resultSearchController = UISearchController()更改为var resultSearchController:UISearchController!我收到致命错误:解开noOfRowInSection中的Optional值时意外发现nil。我有大量的数组,那是在创建错误吗?建议我。
Pawriwes 2015年

我发现,我没有编写情节提要中的委托和数据源,而是编写了代码,问题得以解决。
Pawriwes 2015年

20

这是为我工作的Swift版本(类似于JJH的答案):

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

@alex我将其放在初始化resultSearchController的视图控制器的末尾。
nijm '16

2
您真的不需要,if let因为.removeFromSuperView()如果这样,它什么也不会做superview == nil
NSGangster

11
class SampleClass: UITableViewController, UISearchBarDelegate {

private let searchController =  UISearchController(searchResultsController: nil)

 override func viewDidLoad() {
        super.viewDidLoad()

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

}

10

归纳了一些解决方案,通过完全设置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()

}

我还尝试了此处提供的所有其他解决方案,但都没有抑制警告(尽管搜索控制器确实在运行时可以工作)。做到了。谢谢!
Nicolas Miari 2015年

这也对我有帮助,但是初始化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()
yuzer '16

为什么我们需要在块中初始化?
code4latte

7

在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()
}

我认为这很有帮助!


2

这不是错误。似乎您必须避免在不显示ViewController的情况下创建它们。因此,之后SomeViewController()let variable: SomeViewController您必须调用类似这样的内容self.presentViewController(yourViewController ...etc)。如果不这样做,则在取消分配此视图控制器时会收到此警告。


2

我的工作像这样

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之后调用它


2

在其中创建搜索控制器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()
}

1

我使用了德里克(Derek)的答案,但不得不稍作更改。因为对loadViewIfNeeded()的调用是在定义resultSearchController之前发生的,所以提供的答案对我来说很崩溃。(我的声明是

var resultSearchController: UISearchController!

)。因此,我后来才将其移动,并且它起作用了。

如果我完全不接电话,该错误仍然存​​在,因此我确定这是答案的重要组成部分。我无法在iOS 8上对其进行测试。


1

似乎该视图是延迟加载的,如果您分配了控制器却从不显示它,则该视图不会被加载。在这种情况下,如果控制器已释放,您将收到此警告。您可以显示一次,或调用它的loadViewIfNeed()方法,或使用'let _ = controller.view'强制加载视图以避免此警告。


在iOS 8上,您只能使用'let _ = controller.view'。
大卫

0

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

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()
}

我希望这个对你有用。


这与直接初始化和设置有何不同?我的意思是不使用块语法?
code4latte
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.