How to remove extra space from table view of style- grouped? - ios

Yes I have already tried these from other similar questions but they didn't work:
var frame = CGRect.zero
frame.size.height = .leastNormalMagnitude
tableView.tableHeaderView = UIView(frame: frame)
and
self.automaticallyAdjustsScrollViewInsets = false;
definesPresentationContext = true
Have a look at the extra space I am trying to remove below search bar:
Screenshot
Maybe you can point out an improvement in my code for the same:
import UIKit
class SelectCountryViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating {
struct CellStruct
{
var countryName : String
var countryFlag : String
var countryDialCode : String
}
var cellDatas = [CellStruct]()
var filteredCellDatas = [CellStruct]()
var searchController : UISearchController!
var resultsController = UITableViewController()
var refreshController = UIRefreshControl()
var searchTextField : UITextField!
var searchLoaded = false
var isSearching = false
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self;
var frame = CGRect.zero
frame.size.height = .leastNormalMagnitude
tableView.tableHeaderView = UIView(frame: frame)
self.automaticallyAdjustsScrollViewInsets = false;
//tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
definesPresentationContext = true
configureSearchController()
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancel))
navigationItem.leftBarButtonItem = cancelButton
//self.navigationItem.title = "Select Country"
let searchButton: UIBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(searchButtonAction))
searchButton.image = UIImage(named: "search")
self.navigationItem.rightBarButtonItem = searchButton
refreshController.attributedTitle = NSAttributedString(string: "")
refreshController.addTarget(self, action: #selector(refreshSelector), for: .valueChanged)
tableView.addSubview(refreshController)
guard let path = Bundle.main.path(forResource: "countries", ofType: "json")
else
{
return
}
let url = URL(fileURLWithPath: path)
do
{
let data = try Data (contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
guard let array = json as? [Any] else { return}
for info in array {
guard let userDict = info as? [String: Any] else { return}
guard let code = userDict["code"] as? String else { print("No code found"); return}
guard let dialCode = userDict["dial_code"] as? String else { print("No dial code found"); return}
guard let name = userDict["name"] as? String else { print("No name found"); return}
print("We have: ", code, dialCode, name)
cellDatas.append(CellStruct(countryName: name, countryFlag: code, countryDialCode: dialCode))
}
}
catch
{
print(error)
}
}
func configureSearchController()
{
resultsController.tableView.delegate = self
resultsController.tableView.dataSource = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
//self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
self.searchController.searchBar.scopeButtonTitles = []
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if subViewOne is UITextField {
searchTextField = subViewOne as! UITextField
subViewOne.backgroundColor = UIColor.white
break
}
}
}
self.automaticallyAdjustsScrollViewInsets = false;
extendedLayoutIncludesOpaqueBars = true
definesPresentationContext = true
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
// tableView.setContentOffset(self.navigationItem, animated: true)
searchController.searchBar.barTintColor = UIColor.white
//searchController.searchBar.layer.borderColor = UIColor.white.cgColor
searchTextField.backgroundColor = UIColor.searchBarTextFieldGrey()
return true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
self.searchController.searchBar.showsCancelButton = false
// searchController.searchBar.barTintColor = nil
searchTextField.backgroundColor = UIColor.white
searchController.searchBar.barTintColor = nil
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.backIndicatorImage = nil
}
func updateSearchResults(for searchController: UISearchController) {
//tableView.separatorStyle = UITableViewCellSeparatorStyle.none
if searchController.searchBar.text! == "" {
filteredCellDatas = cellDatas
} else {
// Filter the results
filteredCellDatas = cellDatas.filter { $0.countryName.lowercased().contains(searchController.searchBar.text!.lowercased()) }
}
resultsController.tableView.reloadData()
// tableView.separatorStyle = .none
// tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == resultsController.tableView
{
isSearching = true
return filteredCellDatas.count
}
else
{
isSearching = false
return cellDatas.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell?.separatorInset.left = 15
if cell == nil {
cell = UITableViewCell(style: .value1, reuseIdentifier: "Cell")
cell?.separatorInset.left = 0
}
if tableView == resultsController.tableView
{
cell?.textLabel?.text = filteredCellDatas[indexPath.row].countryName
cell?.detailTextLabel?.text = filteredCellDatas[indexPath.row].countryDialCode
cell?.imageView?.image = UIImage (named: filteredCellDatas[indexPath.row].countryFlag)
}
else
{
cell?.textLabel?.text = cellDatas[indexPath.row].countryName
cell?.detailTextLabel?.text = cellDatas[indexPath.row].countryDialCode
cell?.imageView?.image = UIImage (named: cellDatas[indexPath.row].countryFlag)
}
cell?.textLabel?.textColor = UIColor.labelGray2()
cell?.detailTextLabel?.textColor = UIColor.labelGray2()
cell?.textLabel?.font = UIFont(name:"SF Pro Text", size:15)
cell?.detailTextLabel?.font = UIFont(name:"SF Pro Text", size:15)
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row, indexPath.section)
// let currentCell = tableView.cellForRow(at: indexPath)
if(isSearching)
{
print(filteredCellDatas[indexPath.row].countryFlag)
UserDefaults.standard.set(filteredCellDatas[indexPath.row].countryFlag, forKey: "preferredCountry")
if searchController.isActive {
DispatchQueue.main.async {
self.searchController.dismiss(animated: true, completion: {
self.performSegue(withIdentifier: "unWindFromSelectCountry", sender: nil)
})
}
} else {
// Play segue, dismiss or pop ...
self.performSegue(withIdentifier: "unWindFromSelectCountry", sender: nil)
}
}
else
{
print(cellDatas[indexPath.row].countryFlag)
UserDefaults.standard.set(cellDatas[indexPath.row].countryFlag, forKey: "preferredCountry")
self.performSegue(withIdentifier: "unWindFromSelectCountry", sender: nil)
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return CGFloat.leastNormalMagnitude
}
return tableView.sectionHeaderHeight
}
#objc func cancel(){
navigationController?.popViewController(animated: true)
}
#objc func refreshSelector()
{
if(!searchLoaded)
{
searchLoaded = true
self.tableView.tableHeaderView = searchController.searchBar
print( "Got ya")
}
refreshController.endRefreshing()
}
#objc func searchButtonAction() {
if(!searchLoaded)
{
searchLoaded = true
self.tableView.tableHeaderView = searchController.searchBar
// self.navigationItem.titleView = searchController.searchBar
}
self.searchController.searchBar.becomeFirstResponder()
self.searchController.searchBar.text = ""
// self.navigationItem.rightBarButtonItem = nil
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
As said the table view is of style grouped. I am configuring search bar from code. And updating results therefore using code in the same table view.
Thanks in advance

Maybe it is not a tableHeaderView I presume that it could be particular Section HeaderView try with this:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return CGFloat.leastNormalMagnitude
}
return tableView.sectionHeaderHeight
}
Code is hiding header for first section in the table

Related

Access correct indexPath Row for user

I'm creating a messaging app where users can select who do they want to chat with by a UITableView, the problem is that obviously there needs to be a way to search for an specific user, I had already implemented a UISearchController and I can find the user which I search for. The real problem starts when I select the user with override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) method, because when I select the user, it selects wrong user because of indexPath.row.
Here is some of my code:
NewMessageController:
import UIKit
import Firebase
import FirebaseDatabase
class NewMessageController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating {
var searchController = UISearchController()
var activityIndicator = UIActivityIndicatorView(style: .large)
var aiView = UIView()
let cellId = "cellId"
var users = [User]()
var filteredUsers = [User]()
override func viewDidLoad() {
super.viewDidLoad()
initSearchController()
setUpActivityIndicator()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(didTapCancelButton))
tableView.register(UserCell.self, forCellReuseIdentifier: cellId)
startAI()
fetchUser()
}
func initSearchController() {
searchController.loadViewIfNeeded()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.enablesReturnKeyAutomatically = false
searchController.searchBar.returnKeyType = UIReturnKeyType.done
definesPresentationContext = true
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchController.searchBar.scopeButtonTitles = ["All"]
searchController.searchBar.delegate = self
}
func fetchUser() {
Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User(dictionary: dictionary)
user.id = snapshot.key
// user.setValuesForKeys(dictionary)
self.users.append(user)
DispatchQueue.main.async {
self.stopAI()
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
func setUpActivityIndicator() {
aiView.layer.zPosition = 0.1
aiView.backgroundColor = UIColor.gray
aiView.alpha = 0
aiView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(aiView)
aiView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true
aiView.centerYAnchor.constraint(equalTo: tableView.centerYAnchor, constant: -60).isActive = true
aiView.heightAnchor.constraint(equalToConstant: 150).isActive = true
aiView.widthAnchor.constraint(equalToConstant: 150).isActive = true
aiView.layer.masksToBounds = true
aiView.layer.cornerRadius = 15
activityIndicator.layer.zPosition = 0.2
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: aiView.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: aiView.centerYAnchor).isActive = true
}
func startAI() {
activityIndicator.startAnimating()
aiView.alpha = 0.80
tableView.isUserInteractionEnabled = false
}
func stopAI() {
self.activityIndicator.stopAnimating()
self.tableView.isUserInteractionEnabled = true
self.aiView.alpha = 0
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
var messagesViewController: MessagesViewController?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dismiss(animated: true) {
let selectedUser: User!
if(self.searchController.isActive)
{
selectedUser = self.filteredUsers[indexPath.row]
}
else
{
selectedUser = self.users[indexPath.row]
}
self.messagesViewController?.showChatControllerForUser(user: selectedUser)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (searchController.isActive) {
return filteredUsers.count
}
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
startAI()
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell
let thisUser: User!
if (searchController.isActive) {
thisUser = filteredUsers[indexPath.row]
} else {
thisUser = users[indexPath.row]
}
cell.nameLabel.text = "\(thisUser.firstname!) \(thisUser.surname!)"
cell.usernameLabel.text = thisUser.username
cell.profileImageView.loadImageUsingCacheWithUrlString(urlString: thisUser.userImg!)
cell.timeLabel.text = nil
stopAI()
return cell
}
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scopeButton = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
let searchText = searchBar.text!
filterForSearchTextAndScopeButton(searchText: searchText, scopeButton: scopeButton)
}
func filterForSearchTextAndScopeButton(searchText: String, scopeButton : String = "All") {
filteredUsers = users.filter {
user in
let scopeMatch = (scopeButton == "All" || user.username!.lowercased().contains(scopeButton.lowercased()))
if(searchController.searchBar.text != "") {
let searchTextMatch = user.username!.lowercased().contains(searchText.lowercased())
return scopeMatch && searchTextMatch
} else {
return scopeMatch
}
}
tableView.reloadData()
}
}
UserModel:
import UIKit
class User: NSObject {
#objc var id: String?
#objc var firstname: String?
#objc var surname: String?
#objc var email: String?
#objc var username: String?
#objc var userImg: String?
init(dictionary: [String: AnyObject]) {
self.id = dictionary["id"] as? String
self.firstname = dictionary["firstname"] as? String
self.surname = dictionary["surname"] as? String
self.username = dictionary["username"] as? String
self.email = dictionary["email"] as? String
self.userImg = dictionary["userImg"] as? String
}
}
The function I use for showing ChatLogController:
#objc func showChatControllerForUser(user: User) {
let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
chatLogController.user = user
navigationController?.pushViewController(chatLogController, animated: true)
}
change the way to detect if is search active or not like this.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dismiss(animated: true) {
let selectedUser: User!
if(self.searchController.searchBar.text != "")
{
selectedUser = self.filteredUsers[indexPath.row]
}
else
{
selectedUser = self.users[indexPath.row]
}
self.messagesViewController?.showChatControllerForUser(user: selectedUser)
}
}
some times searchController is active but ther searhbar is "" so is not realizable way to check where is search term or not

Why 'edit actions' are not appear ,but (_:editActionsForRowAt) is called

When I am swiping left, edit actions do not appear. But! All delegete's functions called (canEditRowAt and editActionsForRowAt) Why I can not swipe?
import UIKit
class HikingCustomLocationViewController: UIViewController {
//MARK: - Constants
private let DEFAULT_HEADER_FOOTER_VIEW_ID = "DefaultHeaderFooterViewId"
private let CUSTOM_LOCATION_CELL_ID = "CustomLocationCellId"
// MARK: - UI properties
private lazy var customLocationTableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = ColorHelper.bckgDefaultBlue
tableView.separatorStyle = .singleLine
tableView.separatorColor = ColorHelper.bckgDefaultBlue
tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.indicatorStyle = .white
tableView.backgroundColor = ColorHelper.bckgDefaultBlue
tableView.isHidden = true
// Delagates
tableView.delegate = self
tableView.dataSource = self
// Registration
let defaultHeaderFooterViewNib = UINib(nibName: "DefaultTableViewHeaderFooterView", bundle: nil)
tableView.register(defaultHeaderFooterViewNib, forHeaderFooterViewReuseIdentifier: DEFAULT_HEADER_FOOTER_VIEW_ID)
let customLocationViewCellNib = UINib(nibName: "PlacesTableViewCell", bundle: nil)
tableView.register(customLocationViewCellNib, forCellReuseIdentifier: CUSTOM_LOCATION_CELL_ID)
return tableView
}()
private lazy var userMessageLabel: UILabel = {
let label = UILabel()
label.font = FontHelper.body
label.textAlignment = .center
label.numberOfLines = 0
label.textColor = ColorHelper.bckgTextTextWhite
label.text = NSLocalizedString("PLACESNOTHINGADDED", comment: "")
label.isHidden = true
return label
}()
// MARK: - Dependencies
private lazy var messageBus = MessageBus.sharedInstance
private lazy var globalState = GlobalState.sharedInstance
// MARK: - Props
enum HikingCustomLocationProps {
case loading
case loaded(customLocationGroups: [(tourId: String, customLocations: [CustomLocation])])
}
private var props: HikingCustomLocationProps = .loading {
didSet {
view.setNeedsLayout()
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
switch props {
case .loading:
customLocationTableView.isHidden = true
userMessageLabel.isHidden = true
case .loaded(let customLocationGroups):
if customLocationGroups.isEmpty {
customLocationTableView.isHidden = true
userMessageLabel.isHidden = false
} else {
customLocationTableView.isHidden = false
userMessageLabel.isHidden = true
}
customLocationTableView.reloadData()
}
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("PLACESTITLE", comment: "")
view.backgroundColor = ColorHelper.bckgDefaultBlue
setupMessageBusDelegates()
subscribeMessages()
view.addSubview(customLocationTableView)
view.addSubview(userMessageLabel)
setupConstraints()
if case .product(let appStoreId) = globalState.state {
messageBus.send(msg: GetCustomLocationsAction(appStoreId: appStoreId))
}
}
deinit {
unsubscribeMessages()
}
// MARK: - MessageBus
private var customLocationsReadyMessage: MessageBusDelegate<CustomLocationsReadyMessage>?
private func setupMessageBusDelegates() {
customLocationsReadyMessage = MessageBusDelegate<CustomLocationsReadyMessage>(closure: { [weak self] msg in
if case .product(let appStoreId) = self?.globalState.state {
if msg.appStoreId != appStoreId { return }
self?.props = .loaded(customLocationGroups: msg.customLocationsGroup)
}
if case .tour(let appStoreId, _, _) = self?.globalState.state {
if msg.appStoreId != appStoreId { return }
self?.props = .loaded(customLocationGroups: msg.customLocationsGroup)
}
})
}
private func subscribeMessages() {
messageBus.subscribe(closure: customLocationsReadyMessage)
}
private func unsubscribeMessages() {
messageBus.unsubscribe(closure: customLocationsReadyMessage)
}
// MARK: - Constraints
private func setupConstraints() {
customLocationTableView.translatesAutoresizingMaskIntoConstraints = false
customLocationTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
customLocationTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
customLocationTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
customLocationTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
userMessageLabel.translatesAutoresizingMaskIntoConstraints = false
userMessageLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
userMessageLabel.widthAnchor.constraint(equalToConstant: 288).isActive = true
userMessageLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16).isActive = true
}
}
// MARK: - UITableViewDelegate
extension HikingCustomLocationViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if case .loaded(let customLocationGroups) = props {
guard
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: DEFAULT_HEADER_FOOTER_VIEW_ID) as? DefaultTableViewHeaderFooterView,
let group = customLocationGroups[safe: section]
else { return nil }
headerView.configure(title: ("\(NSLocalizedString("TOUR", comment: "")) \(group.tourId)"), description: nil)
headerView.contentView.backgroundColor = ColorHelper.bckgTableHeaderDarkBlue
return headerView
}
return nil
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if case .product(let appStoreId) = globalState.state {
if case .loaded(let customLocationGroups) = props {
guard
let group = customLocationGroups[safe: indexPath.section],
let cLocation = group.customLocations[safe: indexPath.row],
let tourId = Int(group.tourId)
else { return }
globalState.state = .tour(
appStoreId: appStoreId,
tourId: tourId,
mapSelectionState: .customLocation(id: cLocation.id))
let hikingTourContainerVC = HikingTourContainerViewController(
exitButtonTitile: NSLocalizedString("PLACESTITLE", comment: ""))
self.navigationController?.pushViewController(hikingTourContainerVC, animated: true)
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if case .loaded(let customLocationGroups) = props {
return customLocationGroups.count
}
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if case .loaded(let customLocationGroups) = props {
guard let customLocations = customLocationGroups[safe: section] else { return 0 }
return customLocations.customLocations.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if case .loaded(let customLocationGroups) = props {
guard
let customLocations = customLocationGroups[safe: indexPath.section]?.customLocations,
let cell = tableView.dequeueReusableCell(withIdentifier: CUSTOM_LOCATION_CELL_ID) as? PlacesTableViewCell,
let cLocation = customLocations[safe: indexPath.row]
else { return UITableViewCell() }
cell.configure(noteText: cLocation.note, date: cLocation.date)
setSelectedBackgroundViewFor(cell)
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: NSLocalizedString("DELETE", comment: ""), handler: { (rowAction, indexPath) in
print("Delete action")
})
return [deleteAction]
}
private func setSelectedBackgroundViewFor(_ cell: UITableViewCell) {
let selectedBackgroundView = UIView()
selectedBackgroundView.backgroundColor = ColorHelper.bckg3DefalutBlue
cell.selectedBackgroundView = selectedBackgroundView
}
}
The problem was in calling customLocationTableView.reloadData() inside viewWillLayoutSubviews(). After moving it out, (In my case, I move it to props' didSet) edit actions start to appear.

How do I avoid the extra gap between the search bar and the tableview here and put a separator between the same?

My code produces the following results: Screenshot 1, Screenshot 2
However I am supposed get these:
Requirement
I have tried correcting the same. However I failed miserably and i don't understand what I am doing wrong here. Please help me find what could be wrong here and how I should rectify it. Thanks in advance.
import UIKit
class SelectCountryViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating {
struct CellStruct
{
var countryName : String
var countryFlag : String
var countryDialCode : String
}
var cellDatas = [CellStruct]()
var filteredCellDatas = [CellStruct]()
var searchController : UISearchController!
var resultsController = UITableViewController()
var searchLoaded = false
var isSearching = false
override func viewDidLoad() {
super.viewDidLoad()
configureSearchController()
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancel))
navigationItem.leftBarButtonItem = cancelButton
self.navigationItem.title = "Select Country"
let searchButton: UIBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(searchButtonAction))
searchButton.image = UIImage(named: "search")
self.navigationItem.rightBarButtonItem = searchButton
guard let path = Bundle.main.path(forResource: "countries", ofType: "json")
else
{
return
}
let url = URL(fileURLWithPath: path)
do
{
let data = try Data (contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
guard let array = json as? [Any] else { return}
for info in array {
guard let userDict = info as? [String: Any] else { return}
guard let code = userDict["code"] as? String else { print("No code found"); return}
guard let dialCode = userDict["dial_code"] as? String else { print("No dial code found"); return}
guard let name = userDict["name"] as? String else { print("No name found"); return}
print("We have: ", code, dialCode, name)
cellDatas.append(CellStruct(countryName: name, countryFlag: code, countryDialCode: dialCode))
}
}
catch
{
print(error)
}
self.automaticallyAdjustsScrollViewInsets = false;
}
func configureSearchController()
{
self.navigationController?.navigationBar.shadowImage = UIImage()
resultsController.tableView.delegate = self
resultsController.tableView.dataSource = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.searchController.searchBar.layer.borderWidth = 0
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
searchController.searchBar.layer.borderWidth = 1;
self.searchController.searchBar.scopeButtonTitles = []
searchController.searchBar.barTintColor = UIColor.searchBarBackgroundGrey()
searchController.searchBar.layer.borderColor = UIColor.searchBarBackgroundGrey().cgColor
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if subViewOne is UITextField {
subViewOne.backgroundColor = UIColor.searchBarTextFieldGrey()
break
}
}
}
self.automaticallyAdjustsScrollViewInsets = false;
definesPresentationContext = true
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
searchController.searchBar.barTintColor = UIColor.white
searchController.searchBar.layer.borderColor = UIColor.white.cgColor
return true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
self.searchController.searchBar.showsCancelButton = false
searchController.searchBar.barTintColor = UIColor.searchBarBackgroundGrey()
searchController.searchBar.layer.borderColor = UIColor.searchBarBackgroundGrey().cgColor
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.backIndicatorImage = nil
}
func updateSearchResults(for searchController: UISearchController) {
if searchController.searchBar.text! == "" {
filteredCellDatas = cellDatas
} else {
// Filter the results
filteredCellDatas = cellDatas.filter { $0.countryName.lowercased().contains(searchController.searchBar.text!.lowercased()) }
}
resultsController.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == resultsController.tableView
{
isSearching = true
return filteredCellDatas.count
}
else
{
isSearching = false
return cellDatas.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell?.separatorInset.left = 15
if cell == nil {
cell = UITableViewCell(style: .value1, reuseIdentifier: "Cell")
cell?.separatorInset.left = 0
}
if tableView == resultsController.tableView
{
cell?.textLabel?.text = filteredCellDatas[indexPath.row].countryName
cell?.detailTextLabel?.text = filteredCellDatas[indexPath.row].countryDialCode
cell?.imageView?.image = UIImage (named: filteredCellDatas[indexPath.row].countryFlag)
}
else
{
cell?.textLabel?.text = cellDatas[indexPath.row].countryName
cell?.detailTextLabel?.text = cellDatas[indexPath.row].countryDialCode
cell?.imageView?.image = UIImage (named: cellDatas[indexPath.row].countryFlag)
}
return cell!
}
#objc func cancel(){
navigationController?.popViewController(animated: true)
}
#objc func searchButtonAction() {
searchLoaded = true
self.tableView.tableHeaderView = searchController.searchBar
self.searchController.isActive = true
self.searchController.searchBar.text = ""
self.navigationItem.rightBarButtonItem = nil
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
After search bar is attached to table view it should look : like this and not like this
Add below code in viewDidLoad() :
if #available(iOS 11, *) {
self.tableView.contentInsetAdjustmentBehavior = .never
} else {
self.automaticallyAdjustsScrollViewInsets = false
}
Add below line after setting up your SearchController:
searchController.hidesNavigationBarDuringPresentation = false

Unable to present a UISearchController

I have the following view hierarchy:
UINavigationController
||
\/
LibraryTableViewController: UITableViewController
||
\/
AlbumsCollectionViewController: UICollectionViewController
||
\/
SongsTableViewController: UITableViewController
I want to have a search bar in AlbumsCollectionViewController and a different one in SongsTableViewController that is shown in the navigationItem.titleView.
I have managed to add a working search bar in AlbumsCollectionViewController as follows:
class AlbumsCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController : UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
initSearchBar()
initNavigationBar()
}
private func initSearchBar() {
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsController?.view.isHidden = false
searchController.hidesNavigationBarDuringPresentation = false
self.extendedLayoutIncludesOpaqueBars = true
self.definesPresentationContext = true
searchController.searchBar.backgroundColor = UIColor.black
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSAttributedStringKey.foregroundColor : UIColor.white], for: .normal)
self.navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.isHidden = true
}
private func initNavigationBar() {
searchButton.tintColor = UIColor.white
settingsButton.tintColor = UIColor.white
backButton.tintColor = UIColor.white
self.navigationItem.title = "Artists"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
}
#IBAction func SearchButtonTapped(_ sender: Any) {
showSearchBar()
}
private func showSearchBar(){
navigationItem.titleView?.isHidden = false
searchController.isActive = true
}
}
Note that the search bar is hidden on ViewDidLoad() and is presented when a button is pressed as shown in SearchButtonTapped method.
Now, I am trying to do the same in SongsTableViewController however, the search bar is not showing when tapping the the button (i.e. calling SearchButtonTapped) and I am getting the following message:
Warning: Attempt to present <UISearchController: 0x7f8158812b50> on <MyProject.AlbumsCollectionViewController: 0x7f81588023c0> whose view is not in the window hierarchy!
If I commented the line searchController.isActive = true then the search bar will show, however, it wont be active even if I tapped on it.
Edit
Sorry if I haven't been clear. I have a separate UISearchController in SongsTableViewController. I meant I am using the same logic in both controllers
Also Note if I pushed SongsTableViewController from the navigation controller (i.e the view hierarchy only has 2 controllers (UINavigationController => SongsTableViewController) the search bar works fine
This is most of the Code of SongsTableViewController (omitted non relevant stuff)
import UIKit
import os.log
import MediaPlayer
class SongsTableViewController: UITableViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate ,PlayerDelegate, NowPlayingDelegate, SongCellDelegate, SongsOptionsDelegate {
// MARK: properties
var playerManager: PlayerManager? = nil
var dataManager: DataManager? = nil
var tabVC: TabBarController?
var selectedSong: Song?
lazy var optionsTransitionDelegate = PresentationManager()
lazy var playlistTransitionDelegate = PresentationManager()
var searchController : UISearchController!
#IBOutlet var backgroundView: UIView!
#IBOutlet weak var searchButton: UIBarButtonItem!
#IBOutlet weak var settingsButton: UIBarButtonItem!
var albumID: String?
var artistID: String?
var playlist: Playlist?
var songs = [Song]()
var songIndexMap = [String: Int]()
var filteredSongs = [Song]()
override func viewDidLoad() {
super.viewDidLoad()
self.dataManager = DataManager.getInstance()
self.playerManager = PlayerManager.getInstance()
playlistTransitionDelegate.screenRatio = 2.0 / 3.0
if(self.albumID != nil) {
self.songs = SQLiteManager.getAlbumSongs(albumID: self.albumID!)
} else if(self.artistID != nil) {
self.songs = SQLiteManager.getArtistSongs(artistID: self.artistID!)
} else if (self.playlist != nil) {
self.songs = SQLiteManager.getPlaylistSongs(playlist: self.playlist!)
} else {
dataManager?.songsTableViewController = self
}
for i in 0..<songs.count {
songIndexMap[songs[i].id] = i
}
initSearchBar()
initNavigationBar()
if(songs.count == 0 && (!fullListOfSongs() || fullListOfSongs() && dataManager?.getFullSongsCount() == 0)){
tableView.backgroundView = backgroundView
}
tableView.tableFooterView = UIView()
tabVC = tabBarController as? TabBarController
tabVC?.nowPlayingViewController?.delegate = self
}
private func shouldAutorotate() -> Bool {
return false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return Util.SONG_CELL_HEIGHT
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(isFiltering()) {
return self.filteredSongs.count
} else if (fullListOfSongs()) {
return dataManager!.getFullSongsCount()
}
return self.songs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "SongTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? SongCell else {
fatalError("The dequeued cell is not an instance of SongCell.")
}
var song: Song?
if(fullListOfSongs()) {
if(isFiltering()){
song = self.filteredSongs[indexPath.row]
} else {
song = dataManager?.getSong(index: indexPath.row)
}
} else {
if(isFiltering()){
song = self.filteredSongs[indexPath.row]
} else {
song = self.songs[indexPath.row]
}
}
cell.setAttributes(song: song!)
cell.delegate = self
cell.preservesSuperviewLayoutMargins = false
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
self.tableView.deselectRow(at: indexPath, animated: false)
}
// MARK: - Search Bar
func updateSearchResults(for searchController: UISearchController) {
if (!searchController.isActive) {
hideSearchBar()
tableView.reloadData()
}
if(isSearchBarEmpty()) {
return
}
filterSongs(filter: searchController.searchBar.text!)
tableView.reloadData()
}
private func filterSongs(filter: String) {
if(self.albumID != nil) {
self.filteredSongs = SQLiteManager.getAlbumSongs(albumID: self.albumID!, filter: filter)
} else if(self.artistID != nil) {
self.filteredSongs = SQLiteManager.getArtistSongs(artistID: self.artistID!, filter: filter)
} else if(self.playlist != nil) {
self.filteredSongs = SQLiteManager.getPlaylistSongs(playlist: self.playlist!, filter: filter)
}else {
self.filteredSongs = SQLiteManager.getSongs(filter: filter)
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == "" {
tableView.reloadData()
}
}
private func initSearchBar() {
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsController?.view.isHidden = false
searchController.hidesNavigationBarDuringPresentation = false
self.extendedLayoutIncludesOpaqueBars = true
self.definesPresentationContext = true
searchController.searchBar.backgroundColor = UIColor.black
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSAttributedStringKey.foregroundColor : UIColor.white], for: .normal)
self.navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.isHidden = true
}
private func initNavigationBar() {
searchButton.tintColor = UIColor.white
if (fullListOfSongs()) {
searchButton.isEnabled = false
dataManager?.buttons.append(searchButton)
}
settingsButton.tintColor = UIColor.white
self.navigationItem.title = "Songs"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
}
#IBAction func SearchButtonTapped(_ sender: Any) {
showSearchBar()
}
private func showSearchBar(){
self.navigationItem.titleView?.isHidden = false
self.searchController.isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.searchController.searchBar.becomeFirstResponder()
}
navigationItem.rightBarButtonItems![0].isEnabled = false
navigationItem.rightBarButtonItems![0].image = nil
navigationItem.rightBarButtonItems![1].isEnabled = false
navigationItem.rightBarButtonItems![1].image = nil
}
private func hideSearchBar() {
navigationItem.titleView?.isHidden = true
navigationItem.rightBarButtonItems![0].isEnabled = true
navigationItem.rightBarButtonItems![0].image = UIImage(named: "settings")
navigationItem.rightBarButtonItems![1].isEnabled = true
navigationItem.rightBarButtonItems![1].image = UIImage(named: "search")
}
func isFiltering() -> Bool {
if(searchController == nil){
return false
}
return searchController.isActive && !isSearchBarEmpty()
}
private func isSearchBarEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
private func fullListOfSongs() -> Bool {
return self.playlist == nil && self.albumID == nil && self.artistID == nil
}
}
This worked when I tested. I believe the problem is in SongsTableViewController: self.definesPresentationContext = false. This should be true for the pushed View Controller. (see docs here)
For SongsTableViewController (pushed view controller) add the following:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.definesPresentationContext = true
}
And add this to AlbumsCollectionViewController (initial view controller):
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.definesPresentationContext = false
}
When you are on SongsTableViewController, your AlbumsCollectionViewController is not in the window hierarchy.
What I can understand, you are calling showSearchBar method of AlbumsCollectionViewController from SongsTableViewController. And since you navigated from AlbumsCollectionViewController to SongsTableViewController, your AlbumsCollectionViewController is not in the window hierarchy hence wont able to present the search controller.
To fix try adding a separate searchbar controller in SongsTableViewController just as you previously did in AlbumsCollectionViewController.
Alternatively you can create a seperate viewcontroller, implement search functionality and then present it from both of your controllers.

how to pass data from tableview to tableview like instagram? swift

If users search, the results come out on first table View(searchHome).
And If I select one cell, I can see detail info of this on to next tableView(bookDetail).
So in bookDetail, so only one cell exists like instagram.(it's like instagram my page. In my page I can see many pictures, but I select one, I can only 1 picture with detail info).
but the data of searchHome is not passed to the detailBook.
there are 3 classes with this issue.
One is class for passing data(BookAPIResult)
Another is class of UITableViewController for search(SearchHome)
The other is class of UITableViewController for detailIndo(bookDetail)
class BookAPIresult {
// thumbnail url
var thumbnail : String?
// book title
var title : String?
// book author
var author : String?
// book pub.
var pubnm : String?
// book description
var description : String?
// sellerID
var seller : String?
// list Price
var listPrice : String?
// selling Price
var sellPrice : String?
// UIImage for Thumbnail
var thumbnailImage : UIImage?
}
and SearchHome class is below.
class SearchHome: UITableViewController, UISearchBarDelegate, UISearchControllerDelegate{
// MARK: - Properties
let searchController = UISearchController(searchResultsController: nil)
// var barButton = UIBarButtonItem(title: "Search", style: .Plain, target: nil, action: nil)
let apiKey : String = "cbccaa3f2e893c245785c3b94d980b0c"
var searchString : String = ""
var list = Array<BookAPIresult>()
// MARK: - View Setup
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.searchController.delegate = self
//self.searchController.searchBar.text! = ""
//Setup the status bar
tableView.contentInset.top = 0
// Setup the Search Controller
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
searchController.searchBar.sizeToFit()
self.definesPresentationContext = true
self.tableView.tableHeaderView = searchController.searchBar
//searchController.navigationItem.rightBarButtonItem = barButton
searchController.hidesNavigationBarDuringPresentation = true
// Setup the Scope Bar
searchController.searchBar.scopeButtonTitles = ["Title", "HashTag"]
//tableView.tableHeaderView = searchController.searchBar
// Setup Animation for NavigationBar
navigationController?.hidesBarsOnSwipe = true
searchController.hidesNavigationBarDuringPresentation = false
navigationController?.hidesBarsWhenKeyboardAppears = false
navigationController?.hidesBarsOnTap = true
navigationController?.hidesBarsWhenVerticallyCompact = true
self.refreshControl?.addTarget(self, action: #selector(SearchHome.handleRefresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
// declare hide keyboard swipe
let hideSwipe = UISwipeGestureRecognizer(target: self, action: #selector(SearchHome.hideKeyboardSwipe(_:)))
self.view.addGestureRecognizer(hideSwipe)
// searchController.searchBar.text = searchString
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar){
self.searchString = self.searchController.searchBar.text!
self.list.removeAll()
self.callBookAPI()
self.tableView.reloadData()
self.searchController.active = false
}
override func viewDidAppear(animated: Bool) {
self.searchController.active = false
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.list.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let row = self.list[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("ListCell") as! BookAPIResultCell
cell.title?.text = row.title
cell.author?.text = row.author
dispatch_async(dispatch_get_main_queue(),{ cell.thumb.image = self.getThumbnailImage(indexPath.row)})
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
NSLog("%d 행을 눌렀음",indexPath.row)
var bookInfo = BookAPIresult()
let row = self.list[indexPath.row]
bookInfo.title = row.title
bookInfo.author = row.author
bookInfo.thumbnail = row.thumbnail
bookInfo.pubnm = row.pubnm
bookInfo.listPrice = row.listPrice
bookInfo.sellPrice = ""
bookInfo.seller = "nobody"
bookInfo.description = row.description
//detailVeiw instance
let postInfo = self.storyboard?.instantiateViewControllerWithIdentifier("detailBook") as! detailBook
postInfo.navigationItem.title = bookInfo.title
postInfo.bookDetail.append(bookInfo)
self.navigationController?.pushViewController(postInfo, animated: true)
}
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.view.endEditing(false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func callBookAPI(){
let encodedSearchString = searchString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let apiURI = NSURL(string: "https://apis.daum.net/search/book?apikey=\(self.apiKey)&q=\(encodedSearchString!)&searchType=title&output=json")
let apidata : NSData? = NSData(contentsOfURL: apiURI!)
NSLog("API Result = %#", NSString(data: apidata!, encoding: NSUTF8StringEncoding)!)
do {
let data = try NSJSONSerialization.JSONObjectWithData(apidata!, options:[]) as! NSDictionary
let channel = data["channel"] as! NSDictionary
// NSLog("\(data)")
let result = channel["item"] as! NSArray
var book : BookAPIresult
for row in result {
book = BookAPIresult()
let title = row["title"] as? String
book.title = title
if let authorEx = row["author"] as? String{
book.author = authorEx
}else{
book.author = ""
}
if let pubEX = row["pub_nm"] as? String{
book.pubnm = pubEX
}else{
book.pubnm = ""
}
if let listEX = row["list_price"] as? String{
book.listPrice = "\(listEX)dollar"
}else{
book.listPrice = "0"
}
if let thunmbEX = row["cover_s_url"] as? String{
book.thumbnail = thunmbEX
}else{
book.thumbnail = ""
}
//NSLog("\(book.thumbnail)")
if let description = row["description"] as? String{
if let decodedDescription = description.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding){
book.description = decodedDescription
}else{
book.description = ""
}
}else{
book.description = ""
}
self.list.append(book)
}
} catch {
NSLog("parse error")
}
}
func getThumbnailImage(index : Int) -> UIImage {
let book = self.list[index]
if let savedImage = book.thumbnailImage {
return savedImage
} else {
if book.thumbnail == "" {
book.thumbnailImage = UIImage(named:
"Book Shelf-48.png")
}else{
let url = NSURL(string: book.thumbnail!)
let imageData = NSData(contentsOfURL: url!)
book.thumbnailImage = UIImage(data:imageData!)
}
return book.thumbnailImage!
}
}
func handleRefresh(refreshControl:UIRefreshControl){
self.searchString = self.searchController.searchBar.text!
self.list.removeAll()
self.callBookAPI()
self.tableView.reloadData()
refreshControl.endRefreshing()
}
override func prefersStatusBarHidden() -> Bool {
return false
}
}
extension SearchHome: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
// filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}
And the last is detailBook.
class detailBook : UITableViewController {
var bookDetail = Array<BookAPIresult>()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.navigationController?.hidesBarsOnTap = false
self.navigationController?.hidesBarsWhenVerticallyCompact = false
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.navigationBarHidden = false
self.navigationItem.hidesBackButton = true
let backBtn = UIBarButtonItem(title: "뒤로가기", style: .Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = backBtn
//swipe to back
let backSwipe = UISwipeGestureRecognizer(target: self, action: "back:")
backSwipe.direction = UISwipeGestureRecognizerDirection.Right
self.view.addGestureRecognizer(backSwipe)
//dynamic cell height
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 620
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//define cell
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! detailBookCell
let row = self.bookDetail[indexPath.row]
cell.author.text = row.author
cell.pubnm.text = row.pubnm
cell.listPrice.text = row.listPrice
cell.sellPrice.text = row.sellPrice
cell.detailInfo.text = row.description
cell.detailInfo.sizeToFit()
let url = NSURL(string: row.thumbnail!)
let imageData = NSData(contentsOfURL: url!)
cell.bookImage.image = UIImage(data:imageData!)
return cell
}
//back button
func back(recognizer: UISwipeGestureRecognizer){
self.navigationController?.popViewControllerAnimated(true)
bookDetail.removeAll()
}
}
You array, bookDetail, in the detailBlock class is still nil, so appending will not add any elements. You should first initialize a new array, add your bookInfo item to it, then assign detailBook's bookDetail item to this new array.
You'll need to use the prepareForSegue method in your search view controller and then use performSequeWithIdentifier in your didSelectRowAtIndexPath.
Basically, set up a placeholder object in the bookDetail view controller. In the search view controller set the value of a global object based in didSelecRowAtIndexPath and use the prepareForSegue method to set the placeholder object with the one you just set on your search view controller. When you select a row and it calls the performSegueWithIdentifier method, it will automatically call prepareForSegue and pass the value to the new view controller.

Resources