할당을 해제하는 동안 뷰 컨트롤러의 뷰로드 시도 중… 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-08-29

또한 다음과 같은 더 많은 조사를 수행하십시오. stackoverflow.com/questions/31006045/… 동일한 오류가 있습니다
BaseZen

그래서 저는 신속한 프로젝트를 만들었습니다. 모든 것을 점진적으로 진행했고, 스토리 보드는 없었습니다. 문제 없습니다. 이것이 스토리 보드의 문제입니까? 내가 프로그래밍 말할 때, 나는 더 높으신 양반, 아니 스토리 보드, 모든 코드를 의미하지 않으며 그것을 잘 작동합니다
래리 절임

@BaseZen 전과 })()후에 중단 점을 설정했습니다 })(). 폐쇄가 끝나면 오류가 발생합니다. 나는이 UIViewController아닌가 tableViewController.
MortalMan 2015-08-29

@Larcerax 저는 스토리 보드가 하나 있습니다. 그것은 단지 네비게이션 컨트롤러와의 UIViewController (. 그들이 연결되어있다) 포함
MortalMan

답변:


119

UISearchController의 뷰는 할당을 해제하기 전에 수퍼 뷰에서 제거되어야합니다. (버그라고 추측)

목표 -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](아이폰 OS 9에서 신규)
Leehro

4
@Leehro의 의견이 답입니다. 그것은 나왔다if #available(iOS 9.0, *) { self.searchController?.loadViewIfNeeded() }
Tim

6
나는 dealloc에서 이것을 할 필요가 없다는 @Leehro의 코멘트에 추가하고, 대신 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
나는 당신이 의미하는 바를 변경했습니다. :-) 어쨌든 그것이 질문에 전체 소스를 포함하는 것이 더 낫지 만 스스로 찾는 것이 가장 좋은
이유입니다

나는이 성가신 경고도 받고 있었고 당신의 대답에 따라 모든 것을 고쳤습니다. 그러나 나는 왜! 새로운 UISearchController를 할당하는 대신에 필요합니다 ... 나에게 설명해 주시겠습니까?
SagittariusA

잘 모르겠습니다. 설명도 부탁드립니다.
MortalMan 2015-09-21

var resultSearchController = UISearchController ()에서 var resultSearchController : UISearchController로 변경하면! 치명적인 오류가 발생합니다. noOfRowInSection에서 Optional 값을 언 래핑하는 동안 예기치 않게 nil을 찾았습니다. 배열이 많은데 오류가 발생합니까? 저를 제안하십시오.
Pawriwes

스토리 보드에서 델리게이트 및 데이터 소스를 수행하는 대신 코드를 작성하고 문제가 해결되었음을 알아 냈습니다.
Pawriwes

20

나를 위해 일한 Swift 버전은 다음과 같습니다 (JJHs 답변과 유사).

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

@alex 나는 resultSearchController를 초기화하는 뷰 컨트롤러의 끝에 넣었습니다.
nijm

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

블록에서 초기화해야하는 이유는 무엇입니까?
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의 대답을 사용했지만 약간 변경해야했습니다. resultSearchController가 정의되기 전에 loadViewIfNeeded () 호출이 발생했기 때문에 제공된 답변이 충돌했습니다. (내 선언은

var resultSearchController: UISearchController!

). 그래서 나는 나중에 그것을 옮겼고 작동했습니다.

전화를 완전히 생략하면 버그가 남아 있으므로 대답의 필수 부분이라고 확신합니다. iOS 8에서 테스트 할 수 없었습니다.


1

보기가 지연로드 된 것 같습니다. 컨트롤러를 할당하고 표시하지 않으면보기가로드되지 않습니다. 이 경우 컨트롤러가 할당 해제되면이 경고가 표시됩니다. 한 번 표시하거나 loadViewIfNeed () 메서드를 호출하거나 'let _ = controller.view'를 사용하여이 경고를 피하기 위해 뷰를 강제로로드 할 수 있습니다.


iOS 8에서는 'let _ = controller.view'만 사용할 수 있습니다.
david

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.