[英]How do I push a View Controller that's not in a navigation controller? Swift
I have two ViewControllers, TimeZonesTable
and ResultsTableController
.我有两个 ViewController, TimeZonesTable
和ResultsTableController
。
TimeZonesTable
includes a search bar. TimeZonesTable
包括一个搜索栏。 The results of the search are displayed in ResultsTableController
.搜索ResultsTableController
显示在ResultsTableController
。
Tapping on a result in ResultsTableController
saves the timezone to Core Data and (should) dismiss the ResultsTableController
and reload the TimeZonesTable
showing all of the saved time zones.点击 ResultsTableController 中的ResultsTableController
将时区保存到 Core Data 并且(应该)关闭ResultsTableController
并重新加载TimeZonesTable
显示所有保存的时区。
I cannot get the TimeZonesTable
to reload after dismissing ResultsTableController
.关闭ResultsTableController
后,我无法重新加载TimeZonesTable
。
I've tried reloading the TimeZonesTable
table in the viewWillDisappear
function on ResultsTableController
but it's not working.我试着重装TimeZonesTable
表中的viewWillDisappear
的功能ResultsTableController
但它不工作。
Any help would be appreciated.任何帮助,将不胜感激。
Note: ResultsTableController
is not in a navigation controller.注意: ResultsTableController
不在导航控制器中。
TimeZonesTable时区表
import UIKit
import CoreData
class TimeZonesTable: UITableViewController, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {
var cities: [Zone] = []
var savedCities: [SavedCity] = [] {
didSet {
refreshData()
}
}
var resultsTableController: ResultsTableController!
override func viewDidLoad() {
getSavedCities()
getAvailableCities()
navigationItem.leftBarButtonItem = editButtonItem
navigationItem.leftBarButtonItem?.tintColor = UIColor.label
resultsTableController = ResultsTableController()
let searchController = UISearchController(searchResultsController: resultsTableController)
searchController.searchResultsUpdater = self
searchController.searchBar.autocapitalizationType = .none
if #available(iOS 11.0, *) {
// For iOS 11 and later, place the search bar in the navigation bar.
navigationItem.searchController = searchController
// Make the search bar always visible.
navigationItem.hidesSearchBarWhenScrolling = false
} else {
// For iOS 10 and earlier, place the search controller's search bar in the table view's header.
tableView.tableHeaderView = searchController.searchBar
}
searchController.delegate = self
searchController.searchBar.delegate = self // Monitor when the search button is tapped.
definesPresentationContext = true
}
func getAvailableCities() {
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = Bundle.main.url(forResource: "data", withExtension: "json")!
let task = session.dataTask(with: url) { data, response, error in
// Check for errors
guard error == nil else {
print ("error: \(error!)")
return
}
// Check that data has been returned
guard let content = data else {
print("No data")
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let fetchedData = try decoder.decode([Zone].self, from: content)
for city in fetchedData {
self.cities.append(city)
}
} catch let err {
print("Err", err)
}
}
// Execute the HTTP request
task.resume()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return savedCities.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "timeZoneCell") as! TimeZoneCell
if let city = savedCities[indexPath.row].cityName {
cell.cityName.text = "\(city)"
if let date = savedCities[indexPath.row].formattedDate {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let formattedDate = formatter.date(from: date)
formatter.dateFormat = "EEE, d MMM yyyy"
let dateString = formatter.string(from: formattedDate!)
cell.cityDate.text = dateString
}
if let time = savedCities[indexPath.row].formattedTime {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
let formattedTime = formatter.date(from: time)
formatter.dateFormat = "HH:mm"
let timeString = formatter.string(from: formattedTime!)
cell.currentCityTime.text = timeString
}
}
return cell
}
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
filterContentForSearchText(searchBar.text!)
}
// Filter results based on search text
func filterContentForSearchText(_ searchText: String) {
let filteredArray = cities.filter ({$0.cityName?.lowercased().range(of: searchText.lowercased()) != nil})
resultsTableController.filteredCities = filteredArray
resultsTableController.tableView.reloadData()
}
func getSavedCities() {
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
if let timeZonesFromCD = try? context.fetch(SavedCity.fetchRequest()) {
if let timeZones = timeZonesFromCD as? [SavedCity] {
savedCities = timeZones
tableView.reloadData()
}
}
}
}
func refreshData() {
for city in savedCities {
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let originalUrl = "http://vip.timezonedb.com/v2.1/get-time-zone?key=\(apiKey)&format=json&by=city&city=\(city.cityName!)&country=\(city.countryCode!)"
if let encodedUrl = URL(string: originalUrl.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!) {
let task = session.dataTask(with: encodedUrl) { data, response, error in
// Check for errors
guard error == nil else {
print ("error: \(error!)")
return
}
// Check that data has been returned
guard let content = data else {
print("No data")
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let fetchedData = try decoder.decode(TimeZones.self, from: content)
if let data = fetchedData.zones?.first {
DispatchQueue.main.async {
// Update time and date
city.formatted = data.formatted
city.formattedTime = data.formatted!.components(separatedBy: " ").last!
city.formattedDate = data.formatted!.components(separatedBy: " ").first!
self.tableView.reloadData()
}
}
} catch let err {
print("Err", err)
}
}
// execute the HTTP request
task.resume()
}
}
}
@IBAction func refreshButtonTapped(_ sender: Any) {
getSavedCities()
}
}
ResultsTableController结果表控制器
import UIKit
import CoreData
class ResultsTableController: UITableViewController {
var filteredCities = [Zone]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "searchResultsCell")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredCities.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchResultsCell", for: indexPath)
if let city = filteredCities[indexPath.row].cityName {
if let country = filteredCities[indexPath.row].countryName {
cell.textLabel?.text = "\(city.replacingOccurrences(of: "_", with: " ")), \(country)"
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCity = filteredCities[indexPath.row]
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let originalUrl = "http://vip.timezonedb.com/v2.1/get-time-zone?key=\(apiKey)&format=json&by=city&city=\(selectedCity.cityName!)&country=\(selectedCity.countryCode!)"
if let encodedUrl = URL(string: originalUrl.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!) {
print(encodedUrl)
let task = session.dataTask(with: encodedUrl) { data, response, error in
// Check for errors
guard error == nil else {
print ("error: \(error!)")
return
}
// Check that data has been returned
guard let content = data else {
print("No data")
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let fetchedData = try decoder.decode(TimeZones.self, from: content)
if let city = fetchedData.zones?.first {
DispatchQueue.main.async {
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
let savedCity = SavedCity(context: context)
if let offSet = city.gmtOffset {
savedCity.formattedDate = city.formatted!.components(separatedBy: " ").first!
savedCity.formattedTime = city.formatted!.components(separatedBy: " ").last!
savedCity.formatted = city.formatted
savedCity.countryCode = city.countryCode
savedCity.formattedCityName = city.zoneName!.components(separatedBy: "/").last!
savedCity.countryName = city.countryName
savedCity.gmtOffset = Int32(offSet)
savedCity.zoneName = city.zoneName
savedCity.cityName = city.cityName
}
// Save to core data
(UIApplication.shared.delegate as? AppDelegate)?.saveContext()
}
}
}
} catch let err {
print("Err", err)
}
}
// execute the HTTP request
task.resume()
self.dismiss(animated: true, completion: nil)
}
}
override func viewWillDisappear(_ animated: Bool) {
let vc = TimeZonesTable()
vc.refreshData()
}
}
Set a delegate here and add avaibale to it inside ResultsTableController
在此设置一个委托,并添加avaibale它里面ResultsTableController
resultsTableController = ResultsTableController()
resultsTableController.delegate = self
then然后
// Save to core data
(UIApplication.shared.delegate as? AppDelegate)?.saveContext()
self.delegate?.reload()
self.dismiss(animated: true, completion: nil)
Since you don't have different functionality in the TimeZoneTable vs the ResultTable i would just do the filter in the TimeZoneTable like this:由于您在 TimeZoneTable 与 ResultTable 中没有不同的功能,因此我只会在 TimeZoneTable 中进行过滤,如下所示:
First add a new var:首先添加一个新的var:
var allCities:[Zone] = []
Then change your getCities to copy the data to the new var然后更改您的 getCities 以将数据复制到新的 var
func getSavedCities() {
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
if let timeZonesFromCD = try? context.fetch(SavedCity.fetchRequest()) {
if let timeZones = timeZonesFromCD as? [SavedCity] {
savedCities = timeZones
allCities = timeZones
tableView.reloadData()
}
}
}
}
Finally create an IBAction for text change for your SearchTextView最后为您的 SearchTextView 创建一个用于文本更改的 IBAction
@IBAction func searchTextViewChanged(_ sender: Any) {
savedCities = allCities
savedCities = savedCities.filter {
($0.countryName.lowercased().contains(searchTextView.text) ||
filterString == "")
}
tableView.reloadData()
}
This approach helps you with duplicated code, and you will have less views to manage i don't see what advantage you would get by having 2 almost identical view controllers这种方法可以帮助您处理重复的代码,并且您需要管理的视图更少,我不知道拥有 2 个几乎相同的视图控制器会带来什么好处
Hope this helps even if its not technically exactly what you asked i think is a much cleaner approach to filtering a tableView希望这会有所帮助,即使它在技术上并不完全符合您的要求,我认为这是一种更清洁的过滤 tableView 的方法
You can create protocol and get callback.您可以创建协议并获得回调。 Follow steps and you will get resolved your issue.按照步骤操作,您的问题将得到解决。
Step 1: Create Protocol第 1 步:创建协议
//Step #1
protocol ResultsTableControllerDelegate {
func didSavedTimeZone()
}
Step 2: Assign delegate第 2 步:分配委托
import UIKit
import CoreData
class TimeZonesTable: UITableViewController, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {
//Your code
var resultsTableController: ResultsTableController!
override func viewDidLoad() {
// Your code
resultsTableController = ResultsTableController()
//Step #2
resultsTableController.resultsDelegate = self //Asign delegate here
// Your code
}
}
*Step 3: Implement delegate in your class and do whatever your needs * *第 3 步:在您的班级中实现委托并做任何您需要的事情 *
//Step #3
extension TimeZonesTable: ResultsTableControllerDelegate {
func didSavedTimeZone() {
//Reload your data or Table
}
}
Step 4: Create delegate in result controller第 4 步:在结果控制器中创建委托
import UIKit
import CoreData
class ResultsTableController: UITableViewController {
//Step #4
var resultsDelegate: ResultsTableControllerDelegate?
//Your code
}
Step 5: Call Delegate after saving the data第五步:保存数据后调用Delegate
Note: Please call delegate before dismiss the controller注意:请在解雇控制器之前致电代表
import UIKit
import CoreData
class ResultsTableController: UITableViewController {
//Step #4
var resultsDelegate: ResultsTableControllerDelegate?
//Your code
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Your code
//Step #5
resultsDelegate?.didSavedTimeZone()
self.dismiss(animated: true, completion: nil)
//Your code
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.