2015-08-29 3 views
76

У меня есть код, который создает UISearchController' in my UIVIew's viewDidLoad`.Попытка загрузить представление контроллера представления при его освобождении ... UISearchController

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 на самом деле не моя ситуация (по крайней мере, я так не думаю). Что происходит?

+0

https://xkcd.com/583/ Работает нормально, если я бросаю это в свою таблицу VC 'viewDidLoad()'. Рекомендовать a) включая полный список источников VC и b) убедиться, что ошибка действительно происходит там, где и когда вы думаете. – BaseZen

+0

Кроме того, сделайте больше исследований, таких как: http://stackoverflow.com/questions/31006045/view-appear-with-modal-view-animation-instead-of-show-push-animation, которая имеет ту же ошибку – BaseZen

+0

Итак, Я сделал быстрый проект, сделал все прогматически, никаких раскадровки, и у меня нет проблем, это вопрос раскадровки, который у вас есть, может быть, я не знаю, но я полагаю, вы используете раскадровки, не так ли? Когда я говорю программно, я имею в виду не nibs, ни раскадровки, ни весь код, и он отлично работает – Loxx

ответ

36

Решенный! Это было простое решение. Я изменил этот код

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate { 

    var resultSearchController = UISearchController() 

к этому:

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate { 

    var resultSearchController: UISearchController! 

Это устраняет проблему.

+1

Я изменил его на то, что вы имели в виду. :-) Так или иначе, поэтому включение всего источника в вопрос лучше, но найти его по своему усмотрению лучше ;-) – BaseZen

+0

У меня тоже было это раздражающее предупреждение, и после твоего ответа я исправил все. Но я не знаю, почему! необходимо вместо того, чтобы назначать нового UISearchController ... вы бы меня преувеличили? –

+0

Не уверен, мне тоже хотелось бы пояснить. – MortalMan

114

UISearchController должен быть удален из своего супервизора перед освобождением. (Думаю, это ошибка)

Objective-C ...

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

Swift 3 ...

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

Я боролся с этой проблемой в течение нескольких недель. ^^

+1

Это действительно странно ... Но это тоже помогло мне. Наверное, это ошибка. –

+22

У меня была такая же проблема с 'UISearchControler', которую я выделял в' -viewDidLoad'. Это определенно ошибка - если 'UISearchController' освобожден до загрузки своего представления, это предупреждение появится. Если я нахожусь в поле поиска (тем самым загружая представление), он не появляется. Так что в моем 'dealloc' я вызываю' [self.searchController loadViewIfNeeded] '(новый в iOS 9), – Leehro

+4

@ Комментарий Leehro - это ответ для меня. он появился как 'if #available (iOS 9.0, *) { self.searchController? .loadViewIfNeeded() }' – Tim

19

Вот версия Swift, который работал на меня (подобный toJJHs ответ):

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

Где я должен помещать этот код? – alex

+0

@alex Я положил его в конец контроллера вида, который инициализирует resultSearchController. – mcnijm

+2

У вас действительно НЕ требуется 'if let', так как' .removeFromSuperView() 'ничего не сделает, если' superview == nil' – NSGangster

10

Взлом вместе несколько решений, которые мне удалось получить горные выработки пути добавления строк в viewDidLoad до того полностью настроек UISearchController:

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

} 
+0

Я также пробовал все остальные решения, приведенные здесь, и никто не подавил предупреждение (хотя контроллер поиска ** работает ** во время работы); это сделало это. Спасибо! –

+0

Это тоже помогло мне, но мне пришлось добавить эту строку _after_, я инициализирую UISearchController. 'Self.searchController = ({ пусть контроллер = UISearchController (searchResultsController: ноль) controller.searchResultsUpdater = само controller.dimsBackgroundDuringPresentation = ложь controller.searchBar.delegate = само definesPresentationContext = истинная controller.searchBar.sizeToFit () return controller })() 'then' self.searchController.loadViewIfNeeded()' – yuzer

+0

Зачем нам нужно инициализировать в блоке? – 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. Это вызвало ту же ошибку.

+0

Хороший лорд, то же самое - спасибо за указатель – Nostradamus

1

Я использовал ответ Дерека, но ему пришлось слегка его изменить. Ответ, который был предоставлен, разбился обо мне, потому что вызов loadViewIfNeeded() произошел до определения resultSearchController. (Моя декларация была

var resultSearchController: UISearchController! 

). Поэтому я только что переместил его, и это сработало.

Если я полностью оставил звонок, ошибка осталась, поэтому я уверен, что это неотъемлемая часть ответа. Я не смог проверить его на iOS 8.

1

Это не ошибка. Кажется, что вам нужно избегать создания ViewControllers, не представляя их. Поэтому после SomeViewController() или let variable: SomeViewController вам нужно позвонить примерно так: self.presentViewController(yourViewController ...etc). Если вы этого не сделаете, вы получите это предупреждение, когда этот контроллер будет обработан.

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

Я надеюсь, что это работает для вас.

+0

Как это отличается от инициализации и настройки непосредственно; Я имею в виду без использования синтаксиса блока? – code4latte

7

В Swift 2,2 версия, которая работала для меня

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

Я думаю, что это полезно!

+0

Это сработало для меня! –

11
class SampleClass: UITableViewController, UISearchBarDelegate { 

private let searchController = UISearchController(searchResultsController: nil) 

override func viewDidLoad() { 
     super.viewDidLoad() 

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

} 
+0

Это работает. Но почему это работает? –

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() 
} 
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() решает проблема, но вам нужно вызвать ее после инициализации моря rchController

1

Кажется, что просмотр ленивый, если вы выделили контроллер и никогда его не показываете, представление не загружается. В этом случае, если контроллер освобожден, вы получите это предупреждение. вы можете показать его один раз или вызвать метод loadViewIfNeed() или использовать 'let _ = controller.view', чтобы принудительно загрузить представление, чтобы избежать этого предупреждения.

+0

на iOS 8, вы можете использовать 'let _ = controller.view'. – david

Смежные вопросы