UIAlertController 已经呈现(空)
UIAlertController Already presenting (null)
我有一个应用程序,首先会显示一张地图,其中显示所有靠近我位置的公司。主屏幕有一个搜索按钮,我可以点击它并根据我的特定需要过滤结果
Mapa View Controller 和 Filtrar View Controller 之间的连接是基于自定义协议构建的(根据 https://medium.com/@jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef)。
所有沟通工作正常,我能够过滤并展示符合条件的公司。我的问题是过滤器 returns 什么都没有(没有符合条件的公司)。当发生这种情况时,我想向最终用户提供 UIAltert 作为建议。
警报已触发,但我收到一条错误消息 "Attempt to present on which is already presenting (null)"。
我尝试了
中的其中一项建议
if self.presentedViewController == nil {
// do your presentation of the UIAlertController
// ...
} else {
// either the Alert is already presented, or any other view controller
// is active (e.g. a PopOver)
// ...
let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?
if thePresentedVC != nil {
if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
// nothing to do , AlertController already active
// ...
print("Alert not necessary, already on the screen !")
} else {
// there is another ViewController presented
// but it is not an UIAlertController, so do
// your UIAlertController-Presentation with
// this (presented) ViewController
// ...
thePresentedVC!.presentViewController(...)
print("Alert comes up via another presented VC, e.g. a PopOver")
}
}
}
我看到 "Alert comes up via another presented VC, e.g. a PopOver" 打印出来了,但我不知道如何使用 thePresentedVC!.presentViewController(...)。
我正在使用 XCode 11.2.1 和 IOS 11.
我的详细代码是
警报Class
import UIKit
class Alerta {
var titulo : String
var mensagem : String
init(titulo: String, mensagem: String) {
self.titulo = titulo
self.mensagem = mensagem
}
func getAlerta() -> UIAlertController {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
return alerta
}
}
马帕Class
import UIKit
import MapKit
import ProgressHUD
class MapaViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, FiltroVCDelegate {
@IBOutlet weak var mapa: MKMapView!
var gerenciadorLocalizacao = CLLocationManager()
var anotacaoArray = [MinhaAnotacao]()
// var annotationSearch: [MinhaAnotacao] = [] // Filtered annotation
var anotacao = MinhaAnotacao()
var searchArr: [String] = []
var searching = false
var todasAnotacoes: [(objLat: CLLocationDegrees, objLong: CLLocationDegrees, objName: String, objDesc: String, objId: String, objTel1: String, objTel2: String, objEsp1: String, objEsp2: String, objEst: String, objCid: String)] = []
var clinicasR: [(objLat: CLLocationDegrees, objLong: CLLocationDegrees, objName: String, objDesc: String, objId: String, objTel1: String, objTel2: String, objEsp1: String, objEsp2: String, objEst: String, objCid: String)] = []
@IBOutlet weak var adicionarOutlet: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
mapa.register(MyAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
// Retrieving Logger user data and hidding "add" button if applicable
ProgressHUD.show("Carregando...")
var searching = false
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
ProgressHUD.dismiss()
}
// add annotations to the map
func addAnnotationsToMap() {
anotacaoArray = []
self.mapa.removeAnnotations(mapa.annotations)
if searching {
for oneObject in self.clinicasR {
let umaAnotacao = MinhaAnotacao()
let oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
umaAnotacao.telefone = oneObject.objTel1
umaAnotacao.telefone2 = oneObject.objTel2
umaAnotacao.especialidade1 = oneObject.objEsp1
umaAnotacao.especialidade2 = oneObject.objEsp2
umaAnotacao.estado = oneObject.objEst
umaAnotacao.cidade = oneObject.objCid
umaAnotacao.endereco = oneObject.objDesc
umaAnotacao.latitude = String(oneObject.objLat)
umaAnotacao.longitude = String(oneObject.objLong)
self.anotacaoArray.append(umaAnotacao)
}
} else {
for oneObject in self.todasAnotacoes {
let umaAnotacao = MinhaAnotacao()
let oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
umaAnotacao.telefone = oneObject.objTel1
umaAnotacao.telefone2 = oneObject.objTel2
umaAnotacao.especialidade1 = oneObject.objEsp1
umaAnotacao.especialidade2 = oneObject.objEsp2
umaAnotacao.estado = oneObject.objEst
umaAnotacao.cidade = oneObject.objCid
umaAnotacao.endereco = oneObject.objDesc
umaAnotacao.latitude = String(oneObject.objLat)
umaAnotacao.longitude = String(oneObject.objLong)
self.anotacaoArray.append(umaAnotacao)
}
}
self.mapa.addAnnotations(self.anotacaoArray)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "clinicaDetailsSegue" {
let clinicasDetailsViewController = segue.destination as! ClinicasDetailsViewController
clinicasDetailsViewController.identificador = self.anotacao.identicadorMapa
} else if segue.identifier == "searchSegue" {
if let nav = segue.destination as? UINavigationController, let filterVC = nav.topViewController as? FiltrarViewController {
filterVC.delegate = self
}
}
}
func search(searchAnnotation: [MinhaAnotacao], searchArr: [String]) -> [MinhaAnotacao] {
var searchArr = searchArr
// base case - no more searches - return clinics found
if searchArr.count == 0 {
return searchAnnotation
}
// itterative case - search clinic with next search term and pass results to next search
let foundAnnotation = searchAnnotation.filter { item in
(item.title!.lowercased() as AnyObject).contains(searchArr[0]) ||
item.especialidade1.lowercased().contains(searchArr[0]) ||
item.especialidade2.lowercased().contains(searchArr[0]) ||
item.cidade.lowercased().contains(searchArr[0]) ||
item.estado.lowercased().contains(searchArr[0]) ||
item.latitude.contains(searchArr[0]) || item.longitude.contains(searchArr[0]) || item.endereco.contains(searchArr[0])
}
// remove completed search and call next search
searchArr.remove(at: 0)
return search(searchAnnotation: foundAnnotation, searchArr: searchArr)
}
// From Custom Protocol
func dadosEscolhidos(nomeClinicaFiltro: String, estadoClinicaFiltro: String, cidadeClinicaFiltro: String, especialidade1ClinicaFiltro: String, especialidade2ClinicaFiltro: String) {
searchArr = []
clinicasR = []
searchArr = ["\(nomeClinicaFiltro.lowercased())","\(estadoClinicaFiltro.lowercased())", "\(cidadeClinicaFiltro.lowercased())", "\(especialidade1ClinicaFiltro.lowercased())", "\(especialidade2ClinicaFiltro.lowercased())"]
searchArr = searchArr.filter({ [=12=] != ""})
let annotationSearch = search(searchAnnotation: anotacaoArray, searchArr: searchArr) // Filtered Clinicas
if annotationSearch.count > 0 {
for i in 0...annotationSearch.count - 1 {
self.clinicasR.append((objLat: Double(annotationSearch[i].latitude)!, objLong: Double(annotationSearch[i].longitude)!, objName: annotationSearch[i].title!, objDesc: annotationSearch[i].endereco, objId: annotationSearch[i].identicadorMapa, objTel1: annotationSearch[i].telefone, objTel2: annotationSearch[i].telefone2, objEsp1: annotationSearch[i].especialidade1, objEsp2: annotationSearch[i].especialidade2, objEst: annotationSearch[i].estado, objCid: annotationSearch[i].cidade))
}
searching = true
addAnnotationsToMap()
} else {
if self.presentedViewController == nil {
let alerta = Alerta(titulo: "Erro", mensagem: "Nenhuma clínica atende ao filtro definido")
self.present(alerta.getAlerta(), animated: true, completion: nil)
print( "e Aqui, chegou? \(annotationSearch.count)")
} else {
// either the Alert is already presented, or any other view controller
// is active (e.g. a PopOver)
// ...
let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?
if thePresentedVC != nil {
if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
// nothing to do , AlertController already active
// ...
print("Alert not necessary, already on the screen !")
} else {
// there is another ViewController presented
// but it is not an UIAlertController, so do
// your UIAlertController-Presentation with
// this (presented) ViewController
// ...
//let alerta = Alerta(titulo: "Erro", mensagem: "Nenhuma clínica atende ao filtro definido")
//thePresentedVC!.presentedViewController(alerta)
print("Alert comes up via another presented VC, e.g. a PopOver")
}
}
}
}
}
}
Filtrar 视图控制器
import UIKit
import ProgressHUD
protocol FiltroVCDelegate: class {
func dadosEscolhidos(nomeClinicaFiltro: String, estadoClinicaFiltro: String, cidadeClinicaFiltro: String, especialidade1ClinicaFiltro: String, especialidade2ClinicaFiltro: String)
}
class FiltrarViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
weak var delegate: FiltroVCDelegate?
var nomeSelecionado = ""
var estadosJSON = [Estado]()
var cidades = [Cidade]()
var estado : Estado? // Selected State identifier
var cidade : Cidade? // Selected City identifier
var estadoSelecionado = "" // Selected State
var cidadeSelecionada = "" // Selected City
var especialidadesJSON = [Especialidade]()
var especialidades2 = [Especialidade2]()
var especialidade1 : Especialidade? // Selected Specialty1 identifier
var especialidade2 : Especialidade2? // Selected Specialty2 identifier
var especialidade1Selecionada = ""
var especialidade2Selecionada = ""
let fontName = "HelveticaNeue"
var searchArr = [String]()
@IBOutlet weak var nomeClinica: UITextField!
@IBOutlet weak var especialidadeLabel: UILabel!
@IBOutlet weak var estadoClinicaPicker: UIPickerView!
@IBOutlet weak var especialidade1Picker: UIPickerView!
@IBOutlet weak var especialidade2Picker: UIPickerView!
override func viewDidLoad() {
ProgressHUD.show("Carregando...")
readJsonEstados()
readJsonEspecialidades()
super.viewDidLoad()
nomeClinica.text = ""
especialidadeLabel.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
ProgressHUD.dismiss()
}
@IBAction func aplicarFiltro(_ sender: Any) {
if nomeClinica.text == nil {
nomeClinica.text = ""
}
delegate?.dadosEscolhidos(nomeClinicaFiltro: nomeClinica.text!, estadoClinicaFiltro: estadoSelecionado, cidadeClinicaFiltro: cidadeSelecionada, especialidade1ClinicaFiltro: especialidade1Selecionada, especialidade2ClinicaFiltro: especialidade2Selecionada)
navigationController?.dismiss(animated: true)
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
estadoClinicaPicker.reloadAllComponents()
if pickerView == estadoClinicaPicker {
if component == 0 {
self.estado = self.estadosJSON[row]
self.cidades = self.estadosJSON[row].cidades
estadoClinicaPicker.reloadComponent(1)
estadoClinicaPicker.selectRow(0, inComponent: 1, animated: true)
} else {
self.cidade = self.cidades[row]
estadoClinicaPicker.reloadAllComponents()
}
} else if pickerView == especialidade1Picker {
self.especialidade1 = self.especialidadesJSON[row]
self.especialidades2 = self.especialidadesJSON[row].especialidade2
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
especialidade2Picker.selectRow(0, inComponent: 0, animated: true)
} else if pickerView == especialidade2Picker {
self.especialidade2 = self.especialidades2[row]
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
}
let estadoIndiceSelecionado = estadoClinicaPicker.selectedRow(inComponent: 0)
let cidadeIndiceSelecionada = estadoClinicaPicker.selectedRow(inComponent: 1)
let especialidade1IndiceSelecionado = especialidade1Picker.selectedRow(inComponent: 0)
let especialidade2IndiceSelecionado = especialidade2Picker.selectedRow(inComponent: 0)
if estadoIndiceSelecionado >= 0 {
if cidadeIndiceSelecionada >= 0 {
estadoSelecionado = estadosJSON[estadoIndiceSelecionado].nome
cidadeSelecionada = cidades[cidadeIndiceSelecionada].nome
}
}
if especialidade1IndiceSelecionado >= 0 {
if especialidade2IndiceSelecionado >= 0 {
especialidade1Selecionada = especialidadesJSON[especialidade1IndiceSelecionado].nome
especialidade2Selecionada = especialidadesJSON[especialidade1IndiceSelecionado].especialidade2[especialidade2IndiceSelecionado].nome
}
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
if pickerView == estadoClinicaPicker {
return 2
} else if pickerView == especialidade1Picker {
return 1
} else if pickerView == especialidade2Picker {
return 1
}
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == estadoClinicaPicker {
if component == 0 {
return estadosJSON.count
} else {
return cidades.count
}
} else if pickerView == especialidade1Picker {
return self.especialidadesJSON.count
} else if pickerView == especialidade2Picker {
return especialidades2.count
}
return 1
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var rowTitle = ""
let pickerLabel = UILabel()
pickerLabel.textColor = UIColor.black
if pickerView == estadoClinicaPicker {
if component == 0 {
rowTitle = estadosJSON[row].nome
} else {
rowTitle = cidades[row].nome
}
} else if pickerView == especialidade1Picker {
rowTitle = especialidadesJSON[row].nome
} else if pickerView == especialidade2Picker {
rowTitle = especialidades2[row].nome
}
pickerLabel.text = rowTitle
pickerLabel.font = UIFont(name: fontName, size: 16.0)
pickerLabel.textAlignment = .center
return pickerLabel
}
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
if pickerView == estadoClinicaPicker {
if component == 0 {
return 50
} else {
return 300
}
}
return 300
}
@IBAction func cancel(_ sender: Any) {
navigationController?.dismiss(animated: true)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
func readJsonEstados() {
let url = Bundle.main.url(forResource: "EstadosECidades", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let jsonResult = try JSONDecoder().decode(RootState.self, from: data)
//handles the array of countries on your json file.
self.estadosJSON = jsonResult.estado
self.cidades = self.estadosJSON.first!.cidades
} catch {
let alerta = Alerta(titulo: "Erro ao Carregar", mensagem: "Erro ao carregar Estados e Cidades. Por favor reinicie o app")
self.present(alerta.getAlerta(), animated: true, completion: nil)
}
}
func readJsonEspecialidades() {
let url = Bundle.main.url(forResource: "Especialidades", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let jsonResult = try JSONDecoder().decode(RootEsp.self, from: data)
//handles the array of specialties on your json file.
self.especialidadesJSON = jsonResult.especialidade
self.especialidades2 = self.especialidadesJSON.first!.especialidade2
} catch {
let alerta = Alerta(titulo: "Erro ao Carregar", mensagem: "Erro ao carregar Especialidades. Por favor reinicie o app")
self.present(alerta.getAlerta(), animated: true, completion: nil)
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
谢谢
编辑
Link 到项目 https://github.com/afernandes0001/UIAlertController。
您只需点击登录(无需验证),转到主屏幕、地图、点击搜索和应用 - 无需添加任何数据,因为我已将数据设为静态。
尝试将 VC 传递到您的警报 class 并从那里呈现。
class Alert {
class func show(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
//if more than one VC is presenting, or the same one is presenting twice, this might at least tell you which one (assuming it has a title) or when (if the same one is presenting twice)
print("\(vc.title) is presenting alert")
vc.present(alerta, animated: true)
}
}
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Alert.show(titulo: "title", mensagem: "this is an alert", vc: self)
}
}
与Alert.show(titulo: "", mensagem: "", vc: self)
通话
如果 Alert.show(arguments)
不起作用,您可能没有在函数中使用 class
关键字。如果是这样,您需要先创建一个实例 let alert = Alert()
并使用 alert.show(arguments)
或者您可以修改函数以使用 class 属性并创建 class 的实例,然后调用 instance.show(vc: self)
因为您已经拥有 titulo
和 mensagem
像这样让它成为 UIViewControiller 的扩展:
extension UIViewController {
func showAlert(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
//if more than one VC is presenting, or the same one is presenting twice, this might at least tell you which one (assuming it has a title) or when (if the same one is presenting twice)
print("\(vc.title) is presenting alert")
vc.present(alerta, animated: true)
}}
在你想要的任何地方调用之后:
showAlert(titulo: "YourTitle", mensagem: "YourMessage", vc: self)
import UIKit
class ViewController: UIViewController {
let button = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
button.backgroundColor = .black
button.setTitle("Alert", for: .normal)
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(handleAlert), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.widthAnchor.constraint(equalToConstant: 100).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// Do any additional setup after loading the view.
}
@objc fileprivate func handleAlert() {
OperationQueue.main.addOperation {
showAlert(titulo: "YourTilte", mensagem: "YourMessage", vc: self)
print("On main thread: \(Thread.current.isMainThread)")
}
}
extension UIViewController {
func showAlert(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
vc.present(alerta, animated: true)
}
}
有效:)
我有一个应用程序,首先会显示一张地图,其中显示所有靠近我位置的公司。主屏幕有一个搜索按钮,我可以点击它并根据我的特定需要过滤结果
Mapa View Controller 和 Filtrar View Controller 之间的连接是基于自定义协议构建的(根据 https://medium.com/@jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef)。
所有沟通工作正常,我能够过滤并展示符合条件的公司。我的问题是过滤器 returns 什么都没有(没有符合条件的公司)。当发生这种情况时,我想向最终用户提供 UIAltert 作为建议。
警报已触发,但我收到一条错误消息 "Attempt to present on which is already presenting (null)"。
我尝试了
if self.presentedViewController == nil {
// do your presentation of the UIAlertController
// ...
} else {
// either the Alert is already presented, or any other view controller
// is active (e.g. a PopOver)
// ...
let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?
if thePresentedVC != nil {
if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
// nothing to do , AlertController already active
// ...
print("Alert not necessary, already on the screen !")
} else {
// there is another ViewController presented
// but it is not an UIAlertController, so do
// your UIAlertController-Presentation with
// this (presented) ViewController
// ...
thePresentedVC!.presentViewController(...)
print("Alert comes up via another presented VC, e.g. a PopOver")
}
}
}
我看到 "Alert comes up via another presented VC, e.g. a PopOver" 打印出来了,但我不知道如何使用 thePresentedVC!.presentViewController(...)。
我正在使用 XCode 11.2.1 和 IOS 11.
我的详细代码是
警报Class
import UIKit
class Alerta {
var titulo : String
var mensagem : String
init(titulo: String, mensagem: String) {
self.titulo = titulo
self.mensagem = mensagem
}
func getAlerta() -> UIAlertController {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
return alerta
}
}
马帕Class
import UIKit
import MapKit
import ProgressHUD
class MapaViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, FiltroVCDelegate {
@IBOutlet weak var mapa: MKMapView!
var gerenciadorLocalizacao = CLLocationManager()
var anotacaoArray = [MinhaAnotacao]()
// var annotationSearch: [MinhaAnotacao] = [] // Filtered annotation
var anotacao = MinhaAnotacao()
var searchArr: [String] = []
var searching = false
var todasAnotacoes: [(objLat: CLLocationDegrees, objLong: CLLocationDegrees, objName: String, objDesc: String, objId: String, objTel1: String, objTel2: String, objEsp1: String, objEsp2: String, objEst: String, objCid: String)] = []
var clinicasR: [(objLat: CLLocationDegrees, objLong: CLLocationDegrees, objName: String, objDesc: String, objId: String, objTel1: String, objTel2: String, objEsp1: String, objEsp2: String, objEst: String, objCid: String)] = []
@IBOutlet weak var adicionarOutlet: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
mapa.register(MyAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
// Retrieving Logger user data and hidding "add" button if applicable
ProgressHUD.show("Carregando...")
var searching = false
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
ProgressHUD.dismiss()
}
// add annotations to the map
func addAnnotationsToMap() {
anotacaoArray = []
self.mapa.removeAnnotations(mapa.annotations)
if searching {
for oneObject in self.clinicasR {
let umaAnotacao = MinhaAnotacao()
let oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
umaAnotacao.telefone = oneObject.objTel1
umaAnotacao.telefone2 = oneObject.objTel2
umaAnotacao.especialidade1 = oneObject.objEsp1
umaAnotacao.especialidade2 = oneObject.objEsp2
umaAnotacao.estado = oneObject.objEst
umaAnotacao.cidade = oneObject.objCid
umaAnotacao.endereco = oneObject.objDesc
umaAnotacao.latitude = String(oneObject.objLat)
umaAnotacao.longitude = String(oneObject.objLong)
self.anotacaoArray.append(umaAnotacao)
}
} else {
for oneObject in self.todasAnotacoes {
let umaAnotacao = MinhaAnotacao()
let oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
umaAnotacao.telefone = oneObject.objTel1
umaAnotacao.telefone2 = oneObject.objTel2
umaAnotacao.especialidade1 = oneObject.objEsp1
umaAnotacao.especialidade2 = oneObject.objEsp2
umaAnotacao.estado = oneObject.objEst
umaAnotacao.cidade = oneObject.objCid
umaAnotacao.endereco = oneObject.objDesc
umaAnotacao.latitude = String(oneObject.objLat)
umaAnotacao.longitude = String(oneObject.objLong)
self.anotacaoArray.append(umaAnotacao)
}
}
self.mapa.addAnnotations(self.anotacaoArray)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "clinicaDetailsSegue" {
let clinicasDetailsViewController = segue.destination as! ClinicasDetailsViewController
clinicasDetailsViewController.identificador = self.anotacao.identicadorMapa
} else if segue.identifier == "searchSegue" {
if let nav = segue.destination as? UINavigationController, let filterVC = nav.topViewController as? FiltrarViewController {
filterVC.delegate = self
}
}
}
func search(searchAnnotation: [MinhaAnotacao], searchArr: [String]) -> [MinhaAnotacao] {
var searchArr = searchArr
// base case - no more searches - return clinics found
if searchArr.count == 0 {
return searchAnnotation
}
// itterative case - search clinic with next search term and pass results to next search
let foundAnnotation = searchAnnotation.filter { item in
(item.title!.lowercased() as AnyObject).contains(searchArr[0]) ||
item.especialidade1.lowercased().contains(searchArr[0]) ||
item.especialidade2.lowercased().contains(searchArr[0]) ||
item.cidade.lowercased().contains(searchArr[0]) ||
item.estado.lowercased().contains(searchArr[0]) ||
item.latitude.contains(searchArr[0]) || item.longitude.contains(searchArr[0]) || item.endereco.contains(searchArr[0])
}
// remove completed search and call next search
searchArr.remove(at: 0)
return search(searchAnnotation: foundAnnotation, searchArr: searchArr)
}
// From Custom Protocol
func dadosEscolhidos(nomeClinicaFiltro: String, estadoClinicaFiltro: String, cidadeClinicaFiltro: String, especialidade1ClinicaFiltro: String, especialidade2ClinicaFiltro: String) {
searchArr = []
clinicasR = []
searchArr = ["\(nomeClinicaFiltro.lowercased())","\(estadoClinicaFiltro.lowercased())", "\(cidadeClinicaFiltro.lowercased())", "\(especialidade1ClinicaFiltro.lowercased())", "\(especialidade2ClinicaFiltro.lowercased())"]
searchArr = searchArr.filter({ [=12=] != ""})
let annotationSearch = search(searchAnnotation: anotacaoArray, searchArr: searchArr) // Filtered Clinicas
if annotationSearch.count > 0 {
for i in 0...annotationSearch.count - 1 {
self.clinicasR.append((objLat: Double(annotationSearch[i].latitude)!, objLong: Double(annotationSearch[i].longitude)!, objName: annotationSearch[i].title!, objDesc: annotationSearch[i].endereco, objId: annotationSearch[i].identicadorMapa, objTel1: annotationSearch[i].telefone, objTel2: annotationSearch[i].telefone2, objEsp1: annotationSearch[i].especialidade1, objEsp2: annotationSearch[i].especialidade2, objEst: annotationSearch[i].estado, objCid: annotationSearch[i].cidade))
}
searching = true
addAnnotationsToMap()
} else {
if self.presentedViewController == nil {
let alerta = Alerta(titulo: "Erro", mensagem: "Nenhuma clínica atende ao filtro definido")
self.present(alerta.getAlerta(), animated: true, completion: nil)
print( "e Aqui, chegou? \(annotationSearch.count)")
} else {
// either the Alert is already presented, or any other view controller
// is active (e.g. a PopOver)
// ...
let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?
if thePresentedVC != nil {
if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
// nothing to do , AlertController already active
// ...
print("Alert not necessary, already on the screen !")
} else {
// there is another ViewController presented
// but it is not an UIAlertController, so do
// your UIAlertController-Presentation with
// this (presented) ViewController
// ...
//let alerta = Alerta(titulo: "Erro", mensagem: "Nenhuma clínica atende ao filtro definido")
//thePresentedVC!.presentedViewController(alerta)
print("Alert comes up via another presented VC, e.g. a PopOver")
}
}
}
}
}
}
Filtrar 视图控制器
import UIKit
import ProgressHUD
protocol FiltroVCDelegate: class {
func dadosEscolhidos(nomeClinicaFiltro: String, estadoClinicaFiltro: String, cidadeClinicaFiltro: String, especialidade1ClinicaFiltro: String, especialidade2ClinicaFiltro: String)
}
class FiltrarViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
weak var delegate: FiltroVCDelegate?
var nomeSelecionado = ""
var estadosJSON = [Estado]()
var cidades = [Cidade]()
var estado : Estado? // Selected State identifier
var cidade : Cidade? // Selected City identifier
var estadoSelecionado = "" // Selected State
var cidadeSelecionada = "" // Selected City
var especialidadesJSON = [Especialidade]()
var especialidades2 = [Especialidade2]()
var especialidade1 : Especialidade? // Selected Specialty1 identifier
var especialidade2 : Especialidade2? // Selected Specialty2 identifier
var especialidade1Selecionada = ""
var especialidade2Selecionada = ""
let fontName = "HelveticaNeue"
var searchArr = [String]()
@IBOutlet weak var nomeClinica: UITextField!
@IBOutlet weak var especialidadeLabel: UILabel!
@IBOutlet weak var estadoClinicaPicker: UIPickerView!
@IBOutlet weak var especialidade1Picker: UIPickerView!
@IBOutlet weak var especialidade2Picker: UIPickerView!
override func viewDidLoad() {
ProgressHUD.show("Carregando...")
readJsonEstados()
readJsonEspecialidades()
super.viewDidLoad()
nomeClinica.text = ""
especialidadeLabel.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
ProgressHUD.dismiss()
}
@IBAction func aplicarFiltro(_ sender: Any) {
if nomeClinica.text == nil {
nomeClinica.text = ""
}
delegate?.dadosEscolhidos(nomeClinicaFiltro: nomeClinica.text!, estadoClinicaFiltro: estadoSelecionado, cidadeClinicaFiltro: cidadeSelecionada, especialidade1ClinicaFiltro: especialidade1Selecionada, especialidade2ClinicaFiltro: especialidade2Selecionada)
navigationController?.dismiss(animated: true)
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
estadoClinicaPicker.reloadAllComponents()
if pickerView == estadoClinicaPicker {
if component == 0 {
self.estado = self.estadosJSON[row]
self.cidades = self.estadosJSON[row].cidades
estadoClinicaPicker.reloadComponent(1)
estadoClinicaPicker.selectRow(0, inComponent: 1, animated: true)
} else {
self.cidade = self.cidades[row]
estadoClinicaPicker.reloadAllComponents()
}
} else if pickerView == especialidade1Picker {
self.especialidade1 = self.especialidadesJSON[row]
self.especialidades2 = self.especialidadesJSON[row].especialidade2
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
especialidade2Picker.selectRow(0, inComponent: 0, animated: true)
} else if pickerView == especialidade2Picker {
self.especialidade2 = self.especialidades2[row]
especialidade1Picker.reloadComponent(0)
especialidade2Picker.reloadComponent(0)
}
let estadoIndiceSelecionado = estadoClinicaPicker.selectedRow(inComponent: 0)
let cidadeIndiceSelecionada = estadoClinicaPicker.selectedRow(inComponent: 1)
let especialidade1IndiceSelecionado = especialidade1Picker.selectedRow(inComponent: 0)
let especialidade2IndiceSelecionado = especialidade2Picker.selectedRow(inComponent: 0)
if estadoIndiceSelecionado >= 0 {
if cidadeIndiceSelecionada >= 0 {
estadoSelecionado = estadosJSON[estadoIndiceSelecionado].nome
cidadeSelecionada = cidades[cidadeIndiceSelecionada].nome
}
}
if especialidade1IndiceSelecionado >= 0 {
if especialidade2IndiceSelecionado >= 0 {
especialidade1Selecionada = especialidadesJSON[especialidade1IndiceSelecionado].nome
especialidade2Selecionada = especialidadesJSON[especialidade1IndiceSelecionado].especialidade2[especialidade2IndiceSelecionado].nome
}
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
if pickerView == estadoClinicaPicker {
return 2
} else if pickerView == especialidade1Picker {
return 1
} else if pickerView == especialidade2Picker {
return 1
}
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == estadoClinicaPicker {
if component == 0 {
return estadosJSON.count
} else {
return cidades.count
}
} else if pickerView == especialidade1Picker {
return self.especialidadesJSON.count
} else if pickerView == especialidade2Picker {
return especialidades2.count
}
return 1
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var rowTitle = ""
let pickerLabel = UILabel()
pickerLabel.textColor = UIColor.black
if pickerView == estadoClinicaPicker {
if component == 0 {
rowTitle = estadosJSON[row].nome
} else {
rowTitle = cidades[row].nome
}
} else if pickerView == especialidade1Picker {
rowTitle = especialidadesJSON[row].nome
} else if pickerView == especialidade2Picker {
rowTitle = especialidades2[row].nome
}
pickerLabel.text = rowTitle
pickerLabel.font = UIFont(name: fontName, size: 16.0)
pickerLabel.textAlignment = .center
return pickerLabel
}
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
if pickerView == estadoClinicaPicker {
if component == 0 {
return 50
} else {
return 300
}
}
return 300
}
@IBAction func cancel(_ sender: Any) {
navigationController?.dismiss(animated: true)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
func readJsonEstados() {
let url = Bundle.main.url(forResource: "EstadosECidades", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let jsonResult = try JSONDecoder().decode(RootState.self, from: data)
//handles the array of countries on your json file.
self.estadosJSON = jsonResult.estado
self.cidades = self.estadosJSON.first!.cidades
} catch {
let alerta = Alerta(titulo: "Erro ao Carregar", mensagem: "Erro ao carregar Estados e Cidades. Por favor reinicie o app")
self.present(alerta.getAlerta(), animated: true, completion: nil)
}
}
func readJsonEspecialidades() {
let url = Bundle.main.url(forResource: "Especialidades", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let jsonResult = try JSONDecoder().decode(RootEsp.self, from: data)
//handles the array of specialties on your json file.
self.especialidadesJSON = jsonResult.especialidade
self.especialidades2 = self.especialidadesJSON.first!.especialidade2
} catch {
let alerta = Alerta(titulo: "Erro ao Carregar", mensagem: "Erro ao carregar Especialidades. Por favor reinicie o app")
self.present(alerta.getAlerta(), animated: true, completion: nil)
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
谢谢 编辑
Link 到项目 https://github.com/afernandes0001/UIAlertController。 您只需点击登录(无需验证),转到主屏幕、地图、点击搜索和应用 - 无需添加任何数据,因为我已将数据设为静态。
尝试将 VC 传递到您的警报 class 并从那里呈现。
class Alert {
class func show(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
//if more than one VC is presenting, or the same one is presenting twice, this might at least tell you which one (assuming it has a title) or when (if the same one is presenting twice)
print("\(vc.title) is presenting alert")
vc.present(alerta, animated: true)
}
}
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Alert.show(titulo: "title", mensagem: "this is an alert", vc: self)
}
}
与Alert.show(titulo: "", mensagem: "", vc: self)
如果 Alert.show(arguments)
不起作用,您可能没有在函数中使用 class
关键字。如果是这样,您需要先创建一个实例 let alert = Alert()
并使用 alert.show(arguments)
或者您可以修改函数以使用 class 属性并创建 class 的实例,然后调用 instance.show(vc: self)
因为您已经拥有 titulo
和 mensagem
像这样让它成为 UIViewControiller 的扩展:
extension UIViewController {
func showAlert(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
//if more than one VC is presenting, or the same one is presenting twice, this might at least tell you which one (assuming it has a title) or when (if the same one is presenting twice)
print("\(vc.title) is presenting alert")
vc.present(alerta, animated: true)
}}
在你想要的任何地方调用之后:
showAlert(titulo: "YourTitle", mensagem: "YourMessage", vc: self)
import UIKit
class ViewController: UIViewController {
let button = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
button.backgroundColor = .black
button.setTitle("Alert", for: .normal)
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(handleAlert), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.widthAnchor.constraint(equalToConstant: 100).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// Do any additional setup after loading the view.
}
@objc fileprivate func handleAlert() {
OperationQueue.main.addOperation {
showAlert(titulo: "YourTilte", mensagem: "YourMessage", vc: self)
print("On main thread: \(Thread.current.isMainThread)")
}
}
extension UIViewController {
func showAlert(titulo: String, mensagem: String, vc: UIViewController) {
let alerta = UIAlertController(title: titulo, message: mensagem, preferredStyle: .alert)
let acaoCancelar = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alerta.addAction(acaoCancelar)
vc.present(alerta, animated: true)
}
}
有效:)