割り当て解除中にViewControllerのビューを読み込もうとしています…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それをテーブルVCに入れれば、問題なく動作しviewDidLoad()ます。a)VCソースリスト全体を含め、b)エラーが実際に発生していると思われる場所と時間に発生していることを確認することをお勧めします。
BaseZen 2015

また、次のような詳細な調査を行います:stackoverflow.com/questions/31006045/…同じエラーがあります
BaseZen 2015

だから、私は迅速なプロジェクトを作り、すべてをプログラム的に行い、ストーリーボードはありませんでした、そして私は問題ありません、これはあなたが抱えているストーリーボードの問題ですか、おそらく私は知りませんが、あなたはストーリーボードを使用していると思いますか?私がプログラムで言うとき、私はペン先、ストーリーボード、すべてのコードがなく、それが正常に機能することを意味します
Larry Pickles

@BaseZen私は前にブレークポイントを設定})()して後})()。クロージャが終了すると、エラーがスローされます。私は、UIViewControllerではなく、を持っていますtableViewController
MortalMan 2015

@Larceraxストーリーボードは1つあります。ナビゲーションコントローラーとUIViewControllerのみが含まれています(これらは接続されています)
MortalMan 2015

回答:


119

UISearchControllerのビューは、割り当てを解除する前にスーパービューから削除する必要があります。(バグだと思います)

Objective-C .. ..

-(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() }
ティム

6
@Leehroのコメントに、deallocでこれを行う必要はない、代わりにviewDidLoadでloadViewIfNeededを行うことができるというコメントを追加します。
Clafou 2015

@Leehroと@Clafouのおかげで...呼び出し[self.searchController loadViewIfNeeded];(Obj-C)を追加することが、私のコードの問題を解決した答えです。
andrewbuilder 2016年

36

解決しました!簡単な修正でした。このコードを変更しました

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

これに:

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

これで問題が解決します。


1
私はそれをあなたが意図したものに変えました。:-)とにかく、質問にソース全体を含める方が良いのはそのためですが、自分で見つけるのが最善です;-)
BaseZen 2015

私もこの迷惑な警告を受けていました、そしてあなたの答えに従って、私はすべてを修正しました。しかし、なぜかわかりません!新しいUISearchControllerを割り当てる代わりに必要です...説明していただけますか?
射手座A

よくわかりませんが、説明もお願いします。
MortalMan 2015

var resultSearchController = UISearchController()からvar resultSearchControllerに変更した場合:UISearchController!致命的なエラーが発生します:noOfRowInSectionでオプションの値をアンラップしているときに予期せずnilが見つかりました。配列がたくさんありますが、エラーが発生しますか?私を提案します。
Pawriwes 2015年

ストーリーボードからデリゲートとデータソースを実行する代わりに、コードを記述して問題を解決したことがわかりました。
Pawriwes 2015年

20

これが私のために働いたSwiftバージョンです(JJHの答えに似ています):

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

@alexresultSearchControllerを初期化するViewControllerの最後に配置しました。
nijm 2016年

2
次の場合は何もしないif letので、実際には必要ありません.removeFromSuperView()superview == nil
NSGangster 2016年

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

}

ここに示した他のすべての解決策も試しましたが、警告を抑制したものはありませんでした(ただし、検索コントローラー実行時に機能します)。これはそれをしました。ありがとうございました!
ニコラスミアリ

これは私にも役立ちましたが、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 2016年

ブロックで初期化する必要があるのはなぜですか?
code4latte 2017

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行を含めていませんでした。これにより、同じエラーが発生しました。



2

バグではありません。ViewControllerを提示せずに作成することは避けなければならないようです。したがって、後で、SomeViewController()またはlet variable: SomeViewControllerこのようなものを呼び出す必要がありますself.presentViewController(yourViewController ...etc)。そうしないと、このViewControllerの割り当てが解除されたときにこの警告が表示されます。


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

デレクの答えを使用しましたが、少し変更する必要がありました。resultSearchControllerが定義される前にloadViewIfNeeded()の呼び出しが発生したため、提供された回答がクラッシュしました。(私の宣言は

var resultSearchController: UISearchController!

)。だから私は後でそれを動かしただけでうまくいきました。

通話を完全に省略してもバグは残っていたので、それが答えの本質的な部分であると確信しています。iOS8でテストできませんでした。


1

ビューが遅延ロードされているようです。コントローラーを割り当てて表示しない場合、ビューはロードされません。この場合、コントローラーの割り当てが解除されると、この警告が表示されます。一度表示するか、loadViewIfNeed()メソッドを呼び出すか、「let _ = controller.view」を使用してビューを強制的にロードし、この警告を回避することができます。


iOS 8では、「let _ = controller.view」のみを使用できます。
david 2016

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 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.