Ios 带有SearchController的TableView-未调用Denit
我已将界面生成器中的搜索栏和搜索显示控制器添加到我的应用程序中。我无法将其正确地进行脱硝(dealoc) 它显示以下行为(swift2、ios9):Ios 带有SearchController的TableView-未调用Denit,ios,swift,uitableview,retain,uisearchcontroller,Ios,Swift,Uitableview,Retain,Uisearchcontroller,我已将界面生成器中的搜索栏和搜索显示控制器添加到我的应用程序中。我无法将其正确地进行脱硝(dealoc) 它显示以下行为(swift2、ios9): 用户不搜索任何内容,只从tableView中选择一个项目,DEINIT被调用 用户搜索某个内容(或只需点击搜索栏),取消搜索,从tableView中选择项目,DEINIT被称为 用户搜索某些内容(或只需点击搜索栏),然后从tableView中选择一个项目,不调用Denit:( 如果我在导航控制器中选择“后退”而不是选择某个项目,则会发生相同的行
- 用户不搜索任何内容,只从tableView中选择一个项目,DEINIT被调用
- 用户搜索某个内容(或只需点击搜索栏),取消搜索,从tableView中选择项目,DEINIT被称为
- 用户搜索某些内容(或只需点击搜索栏),然后从tableView中选择一个项目,不调用Denit:(
code removed - refer to COMPLETE CODE at bottom of post.
感谢您的帮助
更新进一步的测试表明,完全从视图控制器中删除progressHud/loadingHud不会影响Denit不会被调用。这一定与tableview或searchcontroller本身有关
更新2我已尝试在我的视图中调用searchBarCancelButtonClicked()方法,但该方法仍无法释放。即使单击“取消”,然后导航到别处,它也会释放
更新3将WillEnglishe/DidEnglishe更改为以下内容对Denit没有任何影响-但没有出现错误的界面问题(感谢Polina)。我正在尝试尽我所能取消发布,但目前为止运气不佳
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
searchBarCancelButtonClicked(searchController.searchBar)
}
override func viewDidDisappear(animated: Bool) {
print("View did disappear")
searchController.searchBar.resignFirstResponder()
searchController.searchBar.endEditing(true)
searchController.active = false
loadingHud.removeFromSuperview()
progressHud.removeFromSuperview()
searchController.searchBar.delegate = nil
searchController.searchResultsUpdater = nil
searchController = nil
tableView = nil
super.viewDidDisappear(true)
}
更新4我仍然没有找到答案。真希望有人能帮忙
更新5响应@ConfusedByCode-我已经更新了以下方法,以便在所有闭包或后台线程操作中使用[unowned self]:
code removed - refer to COMPLETE CODE at bottom of post
我仍然没有看到Denit。我正在检查以确保我没有在某个地方犯下愚蠢的错误
更新6我已经删除了额外的弱self,并确保闭包在
中使用了[weak self]并安全地展开。仍然没有调用DEINIT
更新7更改了两件事,但都没有用-make appDelunowned let appDel
,并将searchBar.resignFirstResponder()放在finishSearch()中。仍然没有收到deinit
完整代码:(表示更新7)
有关正确答案,请参见粘贴在正确代码下的代码
class AirportSearchTBVC: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
var airportData = [Dictionary<String, String>]()
var filteredData = [Dictionary<String, String>]()
var searchController: UISearchController!
unowned let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
var progressHud: ProgressHUD!
var loadingHud: ProgressHUD!
var arrDepOfFlight: String!
var dateOfFlight: NSDate!
var tailNum: String!
var selectedAirportIdent: String!
deinit {
print("TBVC Dealloc")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
progressHud = ProgressHUD(text: "Searching")
loadingHud = ProgressHUD(text: "Loading")
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.delegate = self
view.addSubview(loadingHud)
appDel.backgroundThread(background: { [weak self] in
if let weakSelf = self {
let airportHelper = AirportHelper()
weakSelf.airportData = airportHelper.getAirportSearchData()
}
},
completion: {
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if let weakSelf = self {
if weakSelf.isVisible && weakSelf.isTopViewController {
weakSelf.filteredData = (weakSelf.airportData)
weakSelf.loadingHud.removeFromSuperview()
weakSelf.updateSearchResultsForSearchController(weakSelf.searchController)
weakSelf.tableView.reloadData()
}
}
}
});
}
//MARK: Searchbar methods (All background thread methods are in here)
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchController.searchBar.endEditing(true)
searchController.searchBar.resignFirstResponder()
filteredData = airportData
tableView.reloadData()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
if isVisible && isTopViewController {
if let startCount = searchController.searchBar.text?.length {
if searchController.searchBar.text!.length >= 3 && searchController.searchBar.text!.length == startCount{
view.addSubview(progressHud)
finishSearch()
}
}
}
}
func finishSearch () {
appDel.backgroundThread(background: { [weak self] in
if let weakSelf = self {
if weakSelf.isVisible && weakSelf.isTopViewController {
let searchText = weakSelf.searchController.searchBar.text!.lowercaseString
weakSelf.searchController.searchBar.resignFirstResponder()
weakSelf.filteredData = weakSelf.airportData.filter{
if let ident = $0["ident"] {
if ident.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
if let name = $0["name"] {
if name.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
if let city = $0["municipality"] {
if city.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
return false
}
}
}
},
completion: {
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if let weakSelf = self {
if weakSelf.isVisible && weakSelf.isTopViewController {
weakSelf.tableView.reloadData()
weakSelf.progressHud.removeFromSuperview()
}
}
}
});
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
if isVisible && isTopViewController {
if let startCount = searchController.searchBar.text?.length {
if searchController.searchBar.text!.length >= 3 && searchController.searchBar.text!.length == startCount{
view.addSubview(progressHud)
finishSearch()
}
}
}
}
//MARK: Table view methods:
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 72
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searchController.active {
return filteredData.count
} else {
return airportData.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: AirportSearchTableViewCell
cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! AirportSearchTableViewCell
if searchController.active {
let airportDict = filteredData[indexPath.row]
let airportIdent = airportDict["ident"]
let airportName = airportDict["name"]
let airportRegion = airportDict["iso_region"]
let airportCity = airportDict["municipality"]
cell.loadItem(airportIdent, name: airportName, region: airportRegion, city: airportCity)
} else {
let airportDict = airportData[indexPath.row]
let airportIdent = airportDict["ident"]
let airportName = airportDict["name"]
let airportRegion = airportDict["iso_region"]
let airportCity = airportDict["municipality"]
cell.loadItem(airportIdent, name: airportName, region: airportRegion, city: airportCity)
}
return cell
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
searchBarCancelButtonClicked(searchController.searchBar)
}
override func viewDidDisappear(animated: Bool) {
print("View did disappear")
searchController.searchBar.resignFirstResponder()
searchController.searchBar.endEditing(true)
searchController.active = false
searchController.delegate = nil
searchController.resignFirstResponder()
loadingHud.removeFromSuperview()
progressHud.removeFromSuperview()
searchController.searchBar.delegate = nil
searchController.searchResultsUpdater = nil
searchController.removeFromParentViewController()
searchController = nil
tableView = nil
super.viewDidDisappear(true)
}
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! AirportSearchTableViewCell
selectedAirportIdent = cell.identLbl.text!
self.performSegueWithIdentifier("searchMapVC", sender: nil)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "searchMapVC" {
let mapVC = segue.destinationViewController as! SearchMapController
mapVC.arrDepOfFlight = arrDepOfFlight
mapVC.dateOfFlight = dateOfFlight
mapVC.tailNum = tailNum
mapVC.selectedAirportIdent = selectedAirportIdent
}
}
}
//MARK: EXTENSIONS
extension String {
var length: Int { return characters.count } // Swift 2.0
}
extension UIViewController {
public var isVisible: Bool {
if isViewLoaded() {
return view.window != nil
}
return false
}
public var isTopViewController: Bool {
if self.navigationController != nil {
return self.navigationController?.visibleViewController === self
} else if self.tabBarController != nil {
return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
} else {
return self.presentedViewController == nil && self.isVisible
}
}
}
class AirportSearchTBVC:UITableViewController、UISearchResultsUpdated、UISearchBarDelegate{
var airportData=[Dictionary]()
var filteredData=[Dictionary]()
var searchController:UISearchController!
无主let appDel=UIApplication.sharedApplication().delegate为!AppDelegate
变量progressHud:progressHud!
var loadingHud:ProgressHUD!
var Arrfflight:字符串!
var dateOfFlight:NSDate!
var tailNum:字符串!
var selectedAirportIdent:字符串!
脱硝{
打印(“TBVC解除锁定”)
}
重写func viewDidLoad(){
super.viewDidLoad()
}
覆盖功能视图将出现(动画:Bool){
super.viewwillbeen(true)
progressHud=progressHud(文本:“搜索”)
loadingHud=ProgressHUD(文本:“加载”)
searchController=UISearchController(searchResultsController:nil)
searchController.SearchResultsUpdate=self
searchController.dimsBackgroundDuringPresentation=false
searchController.searchBar.sizeToFit()
tableView.tableHeaderView=searchController.searchBar
DefinePresentationContext=true
searchController.hidesNavigationBarDuringPresentation=false
searchController.searchBar.delegate=self
view.addSubview(loadingHud)
appDel.backgroundThread(背景:{[weak self]in
如果让weakSelf=self{
设airportHelper=airportHelper()
weakSelf.airportData=airportHelper.getAirportSearchData()
}
},
完成:{
dispatch_async(dispatch_get_main_queue()){[weak self]in
如果让weakSelf=self{
如果weakSelf.isVisible&&weakSelf.isTopViewController{
weakSelf.filteredData=(weakSelf.airportData)
weakSelf.loadingHud.removeFromSuperview()
weakSelf.updateSearchResultsForSearchController(weakSelf.searchController)
weakSelf.tableView.reloadData()
}
}
}
});
}
//标记:搜索栏方法(所有后台线程方法都在这里)
func searchBarCancelButtonClicked(搜索栏:UISearchBar){
searchController.searchBar.endEditing(真)
searchController.searchBar.resignFirstResponder()辞职
filteredData=机场数据
tableView.reloadData()
}
func searchBarSearchButtonClicked(搜索栏:UISearchBar){
如果是可见的&&isTopViewController{
如果让startCount=searchController.searchBar.text?长度{
如果searchController.searchBar.text!.length>=3&&searchController.searchBar.text!.length==startCount{
view.addSubview(progressHud)
finishSearch()
}
}
}
}
func finishSearch(){
appDel.backgroundThread(背景:{[weak self]in
如果让weakSelf=self{
如果weakSelf.isVisible&&weakSelf.isTopViewController{
让searchText=weakSelf.searchController.searchBar.text!。小写字母
weakSelf.searchController.searchBar.resignFirstResponder()
weakSelf.filteredData=weakSelf.airportData.filter{
如果let ident=$0[“ident”]{
如果标识小写字符串(搜索文本)!=nil{
返回真值
}
}
如果let name=$0[“name”]{
如果name.lowercasesetring.rangeOfString(searchText)!=nil{
返回真值
}
import UIKit
class AirportSearchTBVC: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
var airportData = [Dictionary<String, String>]()
var filteredData = [Dictionary<String, String>]()
var searchController: UISearchController!
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
var progressHud: ProgressHUD!
var loadingHud: ProgressHUD!
var arrDepOfFlight: String!
var dateOfFlight: NSDate!
var tailNum: String!
var selectedAirportIdent: String!
deinit {
print("TBVC Dealloc")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
progressHud = ProgressHUD(text: "Searching")
loadingHud = ProgressHUD(text: "Loading")
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
//definesPresentationContext = true
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.delegate = self
view.addSubview(loadingHud)
appDel.backgroundThread(background: { [weak self] in
if let weakSelf = self {
let airportHelper = AirportHelper()
weakSelf.airportData = airportHelper.getAirportSearchData()
}
},
completion: {
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if let weakSelf = self {
print("isVisible: \(weakSelf.isVisible)")
print("isTopViewController: \(weakSelf.isTopViewController)")
if weakSelf.isVisible {
weakSelf.filteredData = (weakSelf.airportData)
weakSelf.loadingHud.removeFromSuperview()
weakSelf.updateSearchResultsForSearchController(weakSelf.searchController)
weakSelf.tableView.reloadData()
}
}
}
});
}
//MARK: Searchbar methods (All background thread methods are in here)
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchController.searchBar.endEditing(true)
searchController.searchBar.resignFirstResponder()
filteredData = airportData
tableView.reloadData()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
if let startCount = searchController.searchBar.text?.length {
if searchController.searchBar.text!.length >= 3 && searchController.searchBar.text!.length == startCount{
view.addSubview(progressHud)
finishSearch()
}
}
}
func finishSearch () {
appDel.backgroundThread(background: { [weak self] in
if let weakSelf = self {
let searchText = weakSelf.searchController.searchBar.text!.lowercaseString
//weakSelf.searchController.searchBar.resignFirstResponder()
weakSelf.filteredData = weakSelf.airportData.filter{
if let ident = $0["ident"] {
if ident.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
if let name = $0["name"] {
if name.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
if let city = $0["municipality"] {
if city.lowercaseString.rangeOfString(searchText) != nil {
return true
}
}
return false
}
}
},
completion: {
dispatch_async(dispatch_get_main_queue()) { [unowned self] in
if self.isVisible {
self.tableView.reloadData()
self.progressHud.removeFromSuperview()
}
}
});
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
if let startCount = searchController.searchBar.text?.length {
if searchController.searchBar.text!.length >= 3 && searchController.searchBar.text!.length == startCount{
view.addSubview(progressHud)
finishSearch()
}
}
}
//MARK: Table view methods:
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 72
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searchController.active {
return filteredData.count
} else {
return airportData.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: AirportSearchTableViewCell
cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! AirportSearchTableViewCell
if searchController.active {
let airportDict = filteredData[indexPath.row]
let airportIdent = airportDict["ident"]
let airportName = airportDict["name"]
let airportRegion = airportDict["iso_region"]
let airportCity = airportDict["municipality"]
cell.loadItem(airportIdent, name: airportName, region: airportRegion, city: airportCity)
} else {
let airportDict = airportData[indexPath.row]
let airportIdent = airportDict["ident"]
let airportName = airportDict["name"]
let airportRegion = airportDict["iso_region"]
let airportCity = airportDict["municipality"]
cell.loadItem(airportIdent, name: airportName, region: airportRegion, city: airportCity)
}
return cell
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
searchController.active = false
loadingHud.removeFromSuperview()
progressHud.removeFromSuperview()
}
override func viewDidDisappear(animated: Bool) {
print("View did disappear")
super.viewDidDisappear(true)
}
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! AirportSearchTableViewCell
selectedAirportIdent = cell.identLbl.text!
self.performSegueWithIdentifier("searchMapVC", sender: nil)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "searchMapVC" {
let mapVC = segue.destinationViewController as! SearchMapController
mapVC.arrDepOfFlight = arrDepOfFlight
mapVC.dateOfFlight = dateOfFlight
mapVC.tailNum = tailNum
mapVC.selectedAirportIdent = selectedAirportIdent
}
}
}
//MARK: EXTENSIONS
extension String {
var length: Int { return characters.count } // Swift 2.0
}
extension UIViewController {
public var isVisible: Bool {
if isViewLoaded() {
return view.window != nil
}
return false
}
public var isTopViewController: Bool {
if self.navigationController != nil {
return self.navigationController?.visibleViewController === self
} else if self.tabBarController != nil {
return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
} else {
return self.presentedViewController == nil && self.isVisible
}
}
}
if let safeSelf = weakSelf {
appDel.backgroundThread(background: {
let airportHelper = AirportHelper()
safeSelf.airportData = airportHelper.getAirportSearchData()
},
completion: {
dispatch_async(dispatch_get_main_queue()) {
if safeSelf.isVisible && safeSelf.isTopViewController {
safeSelf.filteredData = (safeSelf.airportData)
safeSelf.loadingHud.removeFromSuperview()
safeSelf.tableView.reloadData()
}
}
});
}
appDel.backgroundThread(background: { [weak self] in
let airportHelper = AirportHelper()
self?.airportData = airportHelper.getAirportSearchData()
},
completion: {
dispatch_async(dispatch_get_main_queue()) { [weak self] in
if self?.isVisible && safeSelf.isTopViewController {
self?.filteredData = (safeSelf.airportData)
self?.loadingHud.removeFromSuperview()
self?.tableView.reloadData()
}
}
});
definesPresentationContext = true // Remove this line...
deinit {
print("TBVC Dealloc")
if let superView = searchController.view.superview
{
superView.removeFromSuperview()
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
searchController?.dismissViewControllerAnimated(false, completion: nil)
}