UISearchController causes black screen Swift 2.0 - ios

I have a strange problem in iOS 9 with Swift 2.0. I added UISearchController in my tableViewController but it causes a strange black screen problem. When I press the search bar and write something it shows my filtered results without any problem but when I tap another tab bar button like Bookmarks and after that when I tap tableViewController which is Most Viewed again it shows black screen like screen shot.
There is my tableViewController;
import UIKit
class CitiesTableViewController: UITableViewController, UISearchResultsUpdating {
// MARK: - Class Properties
private var cities = [String]()
private var veterinaries = [Veterinary]()
private var filteredVeterinaries = [Veterinary]()
private var resultSearchController: UISearchController!
// MARK: - TableViewController Life Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
self.getCitiesList()
self.configureResultsSearchController()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
self.resultSearchController.active = false
}
// MARK: - Configuring Search Bar Controller
private func configureResultsSearchController() {
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.hidesNavigationBarDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.placeholder = "Klinik veya ilçe adı"
self.tableView.tableHeaderView = self.resultSearchController.searchBar
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 }
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.resultSearchController.active { return self.filteredVeterinaries.count }
else { return self.cities.count }
}
// MARK: - Table view Delegate Methods
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (self.resultSearchController.active) {
self.performSegueWithIdentifier(Constants.ShowDetailViewControllerSegueIdentifier, sender: nil)
} else {
self.performSegueWithIdentifier(Constants.ShowTownsTableViewControllerSegueIdentifier, sender: nil)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(Constants.CellIdentifier, forIndexPath: indexPath)
if (self.resultSearchController.active) {
cell.textLabel?.text = self.filteredVeterinaries[indexPath.row].name
cell.detailTextLabel?.text = self.filteredVeterinaries[indexPath.row].address
return cell
} else {
cell.textLabel?.text = self.cities[indexPath.row]
return cell
}
}
// MARK: - PARSE Query Methods
private func getCitiesList() {
let parseQueries = ParseQueries()
parseQueries.downloadListData() {
(let parseResults) in
if let veterinaries = parseResults as? [Veterinary] {
self.veterinaries = veterinaries
for vet in veterinaries {
if let city = vet.city {
self.cities.append(city)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.cities = HelperMethods().removeDuplicatesAndSort(array: self.cities)
self.tableView.reloadData()
}
}
}
}
// MARK: - UISearchController Delegate Methods
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filteredVeterinaries.removeAll(keepCapacity: false)
if let searchBarText = searchController.searchBar.text{
let searchText = searchBarText.lowercaseString
// Searching with Veterinary Name and Veterinary City
self.filteredVeterinaries = self.veterinaries.filter({$0.name?.lowercaseString.rangeOfString(searchText) != nil})
self.filteredVeterinaries += self.veterinaries.filter({$0.town?.lowercaseString.rangeOfString(searchText) != nil})
tableView.reloadData()
}
}
This is the black screen image from iOS 9 simulator same as real device.
I think its deiniting my tableView when I tap the searchBar and it can't init again. Is this a bug or something ?
How can I solve this problem ?
Thank you !

Friend, in your viewDidLoad() insert this code line:
self.definesPresentationContext = true
See how I put (line 29):
click here to see

I recently faced the same issue and I could fix it easily.
self.definesPresentationContext = true was already defined in viewDidLoad() but it didn't solve this issue.
In the above question, maybe you show CitiesTableViewController directly when you tap MostViewed tabbar item.
In order to avoid the black screen, you can embed CitiesTableViewController in a UINavigationController and try to show the navigationcontroller when tapping the tabbar item.
This solution will avoid the black screen issue.

Related

self.performSegue(withIdentifier: "teacherDetail", sender: self) needs two taps

I'm trying to segue from a search result in a tableview controller in swift 3 but when I use self.performSegue(withIdentifier: "teacherDetail", sender: self) it seems to hang when selecting a cell. If I tap the first cell it will show gray like it is selected, and then won't do anything unless I select another cell. Then, it will preform the segue to the detail view controller with the information from the first cell.
import UIKit
var name = ""
class DirectoryTC: UITableViewController, UISearchResultsUpdating {
var teachers = ["Mr. Delano", "Mr. Antani", "Mr. Botelho", "Mr. Braga"]
var filteredTeachers = [String]()
var searchController: UISearchController!
var resultsController = UITableViewController()
override func viewDidLoad() {
super.viewDidLoad()
self.resultsController.tableView.dataSource = self
self.resultsController.tableView.delegate = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
definesPresentationContext = true
}
func updateSearchResults(for searchController: UISearchController) {
self.filteredTeachers = self.teachers.filter{ (teacher:String) -> Bool in
if teacher.lowercased().contains(self.searchController.searchBar.text!.lowercased())
{
return true
}else
{
return false
}
}
self.resultsController.tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableView
{
return self.teachers.count
}else
{
return self.filteredTeachers.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = UITableViewCell()
if tableView == self.tableView
{
cell.textLabel?.text = self.teachers[indexPath.row]
}else
{
cell.textLabel?.text = self.filteredTeachers[indexPath.row]
}
return cell
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
DispatchQueue.main.async(){
if tableView == self.tableView
{
name = self.teachers[indexPath.row]
}else
{
name = self.filteredTeachers[indexPath.row]
}
self.performSegue(withIdentifier: "teacherDetail", sender: self)
}
}
}
And here is the swift file for the view controller I'm trying to segue to.
import UIKit
class DirectoryDetailVC: UIViewController{
#IBOutlet weak var test: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
test.text = name
}
}
make sure that your story board View Controller name is teacherDetail - use
DispatchQueue.main.async { self.performSegue(withIdentifier: "teacherDetail", sender: self)}
instead of
self.performSegue(withIdentifier: "teacherDetail", sender: self)
rmaddy caught it. It was a typo. "Typo - change didDeselectRowAtlectRowAt to didSelectRowAt"

Swift Redundant conformance

I am learning iOS. And now local database on iOS. I'm from Android and finding local DB a bit difficult to understand. I wrote a question which brought me several down votes (instead of simple use of CoreStore or Sync or MagicalRecord). I then started reading this tutorial. After downloading the sample project I'm getting Redundant conformance of 'BeerListViewController' to protocol 'UITableViewDataSource' error in BeerListViewController. Please tell me how can I get it solved.
Here is the code:
import UIKit
import Foundation
class BeerListViewController: UITableViewController {
#IBOutlet weak var sortByControl: UISegmentedControl!
#IBOutlet weak var searchBar: UISearchBar!
let sortKeyName = "name"
let sortKeyRating = "beerDetails.rating"
let wbSortKey = "wbSortKey"
//------------------------------------------
// Rating
var amRatingCtl: AnyObject!
let beerEmptyImage: UIImage = UIImage(named: "beermug-empty")!
let beerFullImage: UIImage = UIImage(named: "beermug-full")!
//#####################################################################
// MARK: - Initialization
required init(coder aDecoder: NSCoder) {
// Automatically invoked by UIKit as it loads the view controller from the storyboard.
amRatingCtl = AMRatingControl(location: CGPointMake(190, 10),
emptyImage: beerEmptyImage,
solidImage: beerFullImage,
andMaxRating: 5)
// A call to super is required after all variables and constants have been assigned values but before anything else is done.
super.init(coder: aDecoder)!
}
//#####################################################################
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Allows data to be passed to the new view controller before the new view is displayed.
// "destinationViewController" must be cast from its generic type (AnyObject) to the specific type used in this app
// (BeerDetailViewController) before any of its properties can be accessed.
let controller = segue.destinationViewController as? BeerDetailViewController
if segue.identifier == "editBeer" {
controller!.navigationItem.rightBarButtonItems = []
//------------------------------------------------------------------------------------
} else if segue.identifier == "addBeer" {
controller!.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel",
style: UIBarButtonItemStyle.Plain,
target: controller,
action: "cancelAdd")
controller!.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done",
style: UIBarButtonItemStyle.Done,
target: controller,
action: "addNewBeer")
}
}
//#####################################################################
// MARK: - UIViewController - Responding to View Events
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//------------------------------------------
// Sorting Key
if !(NSUserDefaults.standardUserDefaults().objectForKey(wbSortKey) != nil) {
// User's sort preference has not been saved. Set default to sort by rating.
NSUserDefaults.standardUserDefaults().setObject(sortKeyRating, forKey: wbSortKey)
}
// Keep the sort control in the UI in sync with the means by which the list is sorted.
if NSUserDefaults.standardUserDefaults().objectForKey(wbSortKey) as! String == sortKeyName {
sortByControl.selectedSegmentIndex = 1
}
//------------------------------------------
fetchAllBeers()
// Cause tableView(cellForRowAtIndexPath) to be called again for every visible row in order to update the table.
tableView.reloadData()
}
//#####################################################################
// MARK: - UIViewController - Managing the View
// viewDidLoad() is called after prepareForSegue().
override func viewDidLoad() {
super.viewDidLoad()
//------------------------------------------
tableView.contentOffset = CGPointMake(0, 44)
}
//#####################################################################
// MARK: - Action Methods
#IBAction func sortByControlChanged(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
NSUserDefaults.standardUserDefaults().setObject(sortKeyRating, forKey: wbSortKey)
fetchAllBeers()
tableView.reloadData()
case 1:
NSUserDefaults.standardUserDefaults().setObject(sortKeyName, forKey: wbSortKey)
fetchAllBeers()
tableView.reloadData()
default:
break
}
}
//#####################################################################
// MARK: - MagicalRecord Methods
func fetchAllBeers() {
}
//#####################################################################
func saveContext() {
}
//#####################################################################
}
//#####################################################################
// MARK: - Table View Data Source
extension BeerListViewController: UITableViewDataSource { // THE ERROR APPEARS HERE
//#####################################################################
// MARK: Configuring a Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//#####################################################################
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
//#####################################################################
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier)
configureCell(cell!, atIndex: indexPath)
return cell!
}
//#####################################################################
// MARK: Helper Methods
func configureCell(cell: UITableViewCell, atIndex indexPath: NSIndexPath) {
//------------------------------------------
// Rating
let ratingText = ""
let myRect = CGRect(x:250, y:0, width:200, height:50)
var ratingLabel = UILabel(frame: myRect)
if !(cell.viewWithTag(20) != nil) {
ratingLabel.tag = 20
ratingLabel.text = ratingText
cell.addSubview(ratingLabel)
} else {
ratingLabel = cell.viewWithTag(20) as! UILabel
}
//----------------------
ratingLabel.text = ratingText
}
//#####################################################################
// MARK: Inserting or Deleting Table Rows
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
//#####################################################################
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// When the commitEditingStyle method is present in a view controller, the table view will automatically enable swipe-to-delete.
if (editingStyle == .Delete) {
}
}
//#####################################################################
}
//#####################################################################
// MARK: - Search Bar Delegate
extension BeerListViewController: UISearchBarDelegate {
// MARK: Editing Text
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text != "" {
performSearch()
} else {
fetchAllBeers()
tableView.reloadData()
}
}
//#####################################################################
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchBar.showsCancelButton = true
}
//#####################################################################
// MARK: Clicking Buttons
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder()
searchBar.text = ""
searchBar.showsCancelButton = false
fetchAllBeers()
tableView.reloadData()
}
//#####################################################################
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// This method is invoked when the user taps the Search button on the keyboard.
searchBar.resignFirstResponder()
performSearch()
}
//#####################################################################
// MARK: Helper Methods
func performSearch() {
tableView.reloadData()
}
//#####################################################################
// MARK: - Bar Positioning Delegate
// UISearchBarDelegate Protocol extends UIBarPositioningDelegate protocol.
// Method positionForBar is part of the UIBarPositioningDelegate protocol.
// This delegate method is required to prevent a gap between the top of the screen and the search bar.
// That happens because, as of iOS 7, the status bar is no longer a separate area but is directly drawn on top of the view controller.
func positionForBar(bar: UIBarPositioning) -> UIBarPosition {
// Tell the search bar to extend under the status bar area.
return .TopAttached
}
//#####################################################################
}
UITableViewController conforms to UITableViewDataSource by definition.
Just delete the protocol conformance
extension BeerListViewController { ...

Searching TableView can't select row

While searching a tableView, every time I try to select a row it just takes me back to the unsearched tableView. What am I missing? the segue works perfectly when not filtering through the table. The ability to select a row just disapears while the searchBar is activated.
import UIKit
import Foundation
class BenchmarkWODViewController: UITableViewController, UISearchResultsUpdating {
var WodList = [WOD]()
var FilteredWodList = [WOD]()
var Keyword = ""
var searchController : UISearchController?
var index = Int()
#IBAction func backButton(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
for wodData in BenchmarkWODs.library {
let wod = WOD(dictionary: wodData)
WodList.append(wod)
}
// Search Bar
self.searchController = UISearchController(searchResultsController: nil)
self.searchController?.searchBar.autocapitalizationType = .None
self.tableView.tableHeaderView = self.searchController?.searchBar
self.searchController?.searchResultsUpdater = self
self.Keyword = ""
definesPresentationContext = true
self.filterByName()
}
func filterByName(){
self.FilteredWodList = self.WodList.filter({ (wod: WOD) -> Bool in
if self.Keyword.characters.count == 0 {
return true
}
if (wod.name?.lowercaseString.rangeOfString(self.Keyword.lowercaseString)) != nil {
return true
}
return false
})
self.tableView.reloadData()
}
// Search Bar Function
func updateSearchResultsForSearchController(searchController: UISearchController) {
Keyword = searchController.searchBar.text!
self.filterByName()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.FilteredWodList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("BenchmarkCell", forIndexPath: indexPath) as UITableViewCell
let wod = self.FilteredWodList[indexPath.row]
if let wodName = wod.name {
cell.textLabel?.text = wodName
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.filterByName()
self.performSegueWithIdentifier("showBenchmarkDetail", sender: nil)
}
}
Figured it out after playing around. Apparently adding the below code corrects the problem.
searchController?.dimsBackgroundDuringPresentation = false
swift 'dimsBackgroundDuringPresentation' was deprecated in iOS 12.0 Use the obscuresBackgroundDuringPresentation property instead.
searchController?.obscuresBackgroundDuringPresentation = false
searchController.obscureBAckgroundDuringPresentation = false is deprecated in IOS 12.0, so for me it was issue with other gesture detector added to the tableview , so make sure you dont have any other gesture detector and touchesview method that distort the normal working flow of tablview's delegate method( didSelectAtRow ), hope it will work,

How to implement search bar like this?

I would like to add a search bar above my collection view and when press it will show like the video showing .https://www.youtube.com/watch?v=mgS2Pzy5eJk .Thanks.
You can directly use iOS default UISearchDisplayController as following tutorial:
UISearchDisplayController Tutorial
Read this tutorial and try it..
Hope it helps...
When the user click the searchBar:
remove or hide the NavigationBar
Adjust the auto layout constraint of search Bar accordingly.
Add animation as you want
Do these thing in func searchBarTextShouldBeginEditing(searchBar: UISearchBar)
func searchBarTextShouldBeginEditing(searchBar: UISearchBar) {
//remove or hide the NavigationBar
//update auto layout constraint
UIView.animateWithduration(0.3) {
self.view.layoutIfNeeded()
}
return true
}
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchResultsUpdating {
#IBOutlet weak var tableview: UITableView!
let unfilteredNFLTeams = ["Bengals", "Ravens", "Browns", "Steelers", "Bears", "Lions", "Packers", "Vikings",
"Texans", "Colts", "Jaguars", "Titans", "Falcons", "Panthers", "Saints", "Buccaneers",
"Bills", "Dolphins", "Patriots", "Jets", "Cowboys", "Giants", "Eagles", "Redskins",
"Broncos", "Chiefs", "Raiders", "Chargers", "Cardinals", "Rams", "49ers", "Seahawks"].sorted()
var filteredNFLTeams: [String]?
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
filteredNFLTeams = unfilteredNFLTeams
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
tableview.tableHeaderView = searchController.searchBar
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let nflTeams = filteredNFLTeams else {
return 0
}
return nflTeams.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "nandhu", for: indexPath)
if let nflTeams = filteredNFLTeams {
let team = nflTeams[indexPath.row]
cell.textLabel!.text = team
}
return cell
}
func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text, !searchText.isEmpty {
filteredNFLTeams = unfilteredNFLTeams.filter { team in
return team.lowercased().contains(searchText.lowercased())
}
} else {
filteredNFLTeams = unfilteredNFLTeams
}
tableview.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

UISearchBar in TableViewController moves up after segue and changing rotation

I have master-detail application, where I use UISearchController to filter cells in UITableViewController (master). I have problem with disappearing UISearchBar after segue. Steps to reproduce problem:
Run app in portrait mode
Touch SearchBar and type search query
Touch one of the cells in TableView and segue to detail controller
While in detail controller, change orientation of the device to landscape mode
Segue back to master. Now SearchBar is partially hidden behind Navigation Bar, even after chaning orientation back to portrait.
My Master controller's MWE:
import UIKit
class MasterViewController: UITableViewController, UISearchResultsUpdating {
var data = ["First", "Second", "Third", "Fourth"]
var searchController: UISearchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
configureSearchController()
}
override func viewWillAppear(animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
super.viewWillAppear(animated)
}
// MARK: - Search Controller
private func configureSearchController() {
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.sizeToFit()
self.definesPresentationContext = true
self.tableView.tableHeaderView = searchController.searchBar
self.tableView.contentOffset = CGPoint(x: 0, y: searchController.searchBar.frame.height)
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let content = data[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.text = content
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let content = data[indexPath.row]
cell.textLabel!.text = content
return cell
}
}
Screenshots:

Resources