This project also click on the textfield pickerview opens, but the data shown above can be entered in the section. How can I turn it off? So just come to my choices below.
If the textfield is clicked, I open the pickerview:
import UIKit
import NVActivityIndicatorView
struct kategoriData {
var text : String?
var id : String?
}
class KonuEkleViewController: UIViewController,UITextFieldDelegate , NVActivityIndicatorViewable , UIPickerViewDataSource , UIPickerViewDelegate{
#IBOutlet weak var txtBaslik: UITextField!
#IBOutlet weak var txtYazi: UITextView!
#IBOutlet weak var txtLink: UITextField!
#IBOutlet weak var btnKonuAc: UIButton!
#IBOutlet weak var txtKategoriSecimi: UITextField!
let size = CGSize(width: 30, height: 30)
let singleton = Global.sharedGlobal
let ConnectString = Connect.ConnectInfo
var kategoriList = [kategoriData]()
let GirisView = GirisViewController()
var secilenKategori : String?
var dbKategoriIsim : String?
var dbKategoriId:String?
override func viewDidLoad() {
super.viewDidLoad()
txtKategoriSecimi.text = "Kategoriyi Seçiniz"
KategoriGetir()
pickerGrafik()
txtYazi.layer.cornerRadius = 10
btnKonuAc.layer.cornerRadius = 10
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(GirisViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
#IBAction func btnKonuEkle(_ sender: Any) {
GirisView.LoadingIcon(tur: 0)
if txtBaslik.text != "" && txtYazi.text != "" && secilenKategori != nil && txtKategoriSecimi.text != "Kategoriyi Seçiniz"
{
KonuEkle(uye: singleton.username, baslik: txtBaslik.text!, mesaj: txtYazi.text, kategori: secilenKategori!, link: txtLink.text!)
}
else
{
GirisView.Bildiri(baslik: "UYARI", mesaj: "Boş Alanları Doldurunuz", tur: 1)
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
self.GirisView.LoadingIcon(tur: 1)
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func KonuEkle(uye:String , baslik:String ,mesaj:String , kategori:String , link:String)
{
var request = URLRequest(url: URL(string:ConnectString.conString + "/KonuEkle")!)
request.httpMethod = "POST"
var postString = "uye="+uye+"&&baslik="+baslik+"&&mesaj="+mesaj+"&&kategori="+kategori+"&&link="+link
postString = postString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil
{
print("error")
}
if let urlContent = data
{
do
{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(jsonResult)
if let gelenDizi = jsonResult as? NSArray
{
for i in 0..<gelenDizi.count
{
if let gelenMesaj = (gelenDizi[i] as? NSDictionary)?["mesaj"] as? String
{
DispatchQueue.main.async {
self.Sonuc(mesaj:gelenMesaj)
}
}
}
}
}
catch
{
print("server hatası")
}
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
self.GirisView.LoadingIcon(tur: 1)
}
}
task.resume()
}
func Sonuc(mesaj:String)
{
var mesajSonuc = ""
var mesajBaslik = ""
if mesaj == "basarili"
{
mesajSonuc = "Konu Açıldı"
mesajBaslik = "Bilgi"
}
else
{
mesajSonuc = "Bir Hata Oluştu Lütfen Destek Bölümünden Bize Ulaşın"
mesajBaslik = "Uyarı"
}
let appearance = SCLAlertView.SCLAppearance(showCloseButton: false)
let alert = SCLAlertView(appearance: appearance)
_ = alert.addButton("Tamam") {
self.txtLink.text = ""
self.txtYazi.text = ""
self.txtBaslik.text = ""
self.navigationController!.popViewController(animated: true)
}
if mesajBaslik == "Bilgi"
{
_ = alert.showSuccess(mesajBaslik, subTitle:mesajSonuc)
}
else
{
_ = alert.showNotice(mesajBaslik, subTitle:mesajSonuc)
}
}
func pickerGrafik()
{
let pickerView = UIPickerView()
pickerView.delegate = self
txtKategoriSecimi.inputView = pickerView
let toolBar = UIToolbar(frame: CGRect(x: 0, y: self.view.frame.size.height/6, width: self.view.frame.size.width, height: 40.0))
toolBar.layer.position = CGPoint(x: self.view.frame.size.width/2, y: self.view.frame.size.height-20.0)
toolBar.barStyle = UIBarStyle.blackTranslucent
toolBar.tintColor = UIColor.white
toolBar.backgroundColor = UIColor.black
let defaultButton = UIBarButtonItem(title: "İptal", style: UIBarButtonItemStyle.plain, target: self, action: #selector(KonuEkleViewController.tappedToolBarBtn))
let doneButton = UIBarButtonItem(title: "Tamam", style: UIBarButtonItemStyle.done, target: self, action: #selector(KonuEkleViewController.donePressed))
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width / 3, height: self.view.frame.size.height))
label.font = UIFont(name: "Helvetica", size: 12)
label.backgroundColor = UIColor.clear
label.textColor = UIColor.white
label.text = "Kategoriyi Seçiniz"
label.textAlignment = NSTextAlignment.center
let textBtn = UIBarButtonItem(customView: label)
toolBar.setItems([defaultButton,flexSpace,textBtn,flexSpace,doneButton], animated: true)
txtKategoriSecimi.inputAccessoryView = toolBar
}
func donePressed(_ sender: UIBarButtonItem) {
txtKategoriSecimi.resignFirstResponder()
}
func tappedToolBarBtn(_ sender: UIBarButtonItem) {
txtKategoriSecimi.resignFirstResponder()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return kategoriList.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return kategoriList[row].text
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
txtKategoriSecimi.text = kategoriList[row].text
secilenKategori = kategoriList[row].id
}
func KategoriGetir()
{
kategoriList.removeAll()
//SADECE 1 DEFA EKLENIYOR
self.kategoriList.append(kategoriData.init(text: "Kategoriyi Seçiniz", id: "1"))
GirisView.LoadingIcon(tur: 0)
var request = URLRequest(url: URL(string:ConnectString.conString + "/KategoriGetir")!)
request.httpMethod = "POST"
var postString = "tur=1&&kategori="
postString = postString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil
{
print("error")
}
if let urlContent = data
{
do
{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(jsonResult)
if let gelenDizi = jsonResult as? NSArray
{
for i in 0..<gelenDizi.count
{
if let gelenKategori = (gelenDizi[i] as? NSDictionary)?["kategoriisim"] as? String
{
self.dbKategoriIsim = gelenKategori
}
if let gelenId = (gelenDizi[i] as? NSDictionary)?["id"] as? String
{
self.dbKategoriId = gelenId
}
self.kategoriList.append(kategoriData.init(text: self.dbKategoriIsim, id: self.dbKategoriId))
}
}
}
catch
{
print("error")
}
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
self.GirisView.LoadingIcon(tur: 1)
}
}
task.resume()
}
}
You can implement the UITextFieldDelegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
To return false so that entering any character by hand would be prevented.
This isn't an actual problem when running on a real iPhone device, since no keyboard will be available to do the typing :)
This is only seems like an issue when running on the iOS simulator, since you can then use your Mac keyboard as well.
Having said, you definitely should go with Mr. Hedgehog answer if you still want to block text input to your field.
If, besides blocking input, you may also want to hide the caret on the text field, also try this:
class PickerBasedTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect { .zero }
}
If you want to prevent user from using paste action, you can make a subclass of UITextField to override canPerformAction.
public class PickerUITextField: UITextField {
override public func canPerformAction(_ action: Selector, withSender
sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
Here is a doc for list of actions.
Related
I am using a pod called SpreadsheetView to show data, from a json, in a grid but I don't know how to show them because with this pod it is necessary to invoke an array for each column.
I would like to order this data from my json in the corresponding columns and also when touching a cell in a row I was taken to a view to show the related data.
Attached the code of what I have done.
The view that I use to display the data
import UIKit
import SpreadsheetView
class TiendasViewController: UIViewController, SpreadsheetViewDataSource, SpreadsheetViewDelegate, ConsultaModeloProtocol{
let headers = ["Sucursal", "Venta total", "Tickets", "Piezas", "Pzs/Ticket", "Ticket prom.", "Utilidad", "Última venta"]
var feedItems = [DetallesConsulta]()
func itemConsulta(LaConsulta: [DetallesConsulta]) {
feedItems = LaConsulta
self.tablaTiendas.reloadData()
}
var selectDato : DetallesConsulta = DetallesConsulta()
private let tablaTiendas = SpreadsheetView()
override func viewDidLoad() {
super.viewDidLoad()
let consultaModelo = ConsultaModelo()
consultaModelo.ElDelegado = self
consultaModelo.downloadConsulta()
tablaTiendas.dataSource = self
tablaTiendas.delegate = self
tablaTiendas.contentInset = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)
tablaTiendas.intercellSpacing = CGSize(width: 4, height: 1)
tablaTiendas.gridStyle = .none
tablaTiendas.gridStyle = .solid(width: 1, color: .blue)
tablaTiendas.register(SucursalesCell.self, forCellWithReuseIdentifier: String(describing: SucursalesCell.self))
tablaTiendas.register(DateCell.self, forCellWithReuseIdentifier: String(describing: DateCell.self))
view.addSubview(tablaTiendas)
print("Imprimiendo los feeditems: ", feedItems)
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tablaTiendas.frame = CGRect(x: 0, y:216, width: view.frame.size.width, height: view.frame.size.height-100)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tablaTiendas.flashScrollIndicators()
}
func spreadsheetView(_ spreadsheetView: SpreadsheetView, cellForItemAt indexPath: IndexPath) -> Cell? {
if case (0...(headers.count), 0) = (indexPath.column, indexPath.row) {
let cell = spreadsheetView.dequeueReusableCell(withReuseIdentifier: String(describing: DateCell.self), for: indexPath) as! DateCell
cell.label.text = headers[indexPath.column - 0]
return cell
} else if case(0, 1...(sucursales.count + 1)) = (indexPath.column, indexPath.row){
let cell = spreadsheetView.dequeueReusableCell(withReuseIdentifier: String(describing: SucursalesCell.self), for: indexPath) as! SucursalesCell
cell.label.text = sucursales[indexPath.row - 1]
return cell
}
/*
let cell = tablaTiendas.dequeueReusableCell(withReuseIdentifier: MyLabelCell.identifier, for: indexPath) as! MyLabelCell
if indexPath.row == 0 {
cell.setup(with: headers[indexPath.column])
cell.backgroundColor = .systemBlue
}
return cell
*/
return nil
}
func numberOfColumns(in spreadsheetView: SpreadsheetView) -> Int {
return headers.count
}
func numberOfRows(in spreadsheetView: SpreadsheetView) -> Int {
return 1 + sucursales.count
}
func spreadsheetView(_ spreadsheetView: SpreadsheetView, widthForColumn column: Int) -> CGFloat {
return 200
}
func spreadsheetView(_ spreadsheetView: SpreadsheetView, heightForRow row: Int) -> CGFloat {
if case 0 = row{
return 24
}else{
return 55
}
}
func frozenColumns(in spreadsheetView: SpreadsheetView) -> Int {
return 1
}
}
class MyLabelCell: Cell {
private let label = UILabel()
public func setup(with text: String){
label.text = text
label.textAlignment = .center
contentView.addSubview(label)
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame = contentView.bounds
}
}
class DateCell: Cell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.frame = bounds
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.font = UIFont.boldSystemFont(ofSize: 15)
label.textAlignment = .center
contentView.addSubview(label)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class SucursalesCell: Cell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.frame = bounds
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: UIFont.Weight.medium)
label.textAlignment = .center
contentView.addSubview(label)
}
override var frame: CGRect {
didSet {
label.frame = bounds.insetBy(dx: 6, dy: 0)
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
The model to download the json
import UIKit
import Foundation
protocol ConsultaModeloProtocol: AnyObject {
func itemConsulta (LaConsulta: [DetallesConsulta])
}
var fechaPresente: String = ""
var fechaPasada: String = ""
let elToken : String = UserDefaults.standard.string(forKey: "token")!
let helper = Helper()
class ConsultaModelo: NSObject {
weak var ElDelegado : ConsultaModeloProtocol!
let URLPath = helper.host+"tiendas"
func downloadConsulta(){
var request = URLRequest(url: URL(string: URLPath)!)
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(elToken)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
let SessionDefault = Foundation.URLSession(configuration: URLSessionConfiguration.ephemeral)
URLCache.shared.removeAllCachedResponses()
let task = SessionDefault.dataTask(with: request){
(data, response, error)in
if error != nil {
print("Error al descargar la consulta")
}else{
print("Datos descargados")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data: Data){
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
}catch let error as NSError{
print(error)
}
var jsonElement = NSDictionary()
var detalles = [DetallesConsulta]()
for i in 0 ..< jsonResult.count{
jsonElement = jsonResult[i] as! NSDictionary
let detalle = DetallesConsulta()
let Fecha = jsonElement["Fecha"]
let Sucursal = jsonElement["Sucursal"]
let Suc = jsonElement["Suc"]
let VentaTotal = jsonElement["Venta_Total"]
let NoFolios = jsonElement["N_Folios"]
let Piezas = jsonElement["Piezas"]
let PzaxTicket = jsonElement["PzaxTicket"]
let TicketPromedio = jsonElement["TicketPromedio"]
detalle.Fecha = Fecha as? String
detalle.Sucursal = Sucursal as? String
detalle.Suc = Suc as? String
detalle.VentaTotal = VentaTotal as? String
detalle.NoFolios = NoFolios as? Int
detalle.Piezas = Piezas as? String
detalle.PzaxTicket = PzaxTicket as? String
detalle.TicketPromedio = TicketPromedio as? String
detalles.append(detalle)
}
DispatchQueue.main.async(execute: { ()-> Void in
self.ElDelegado.itemConsulta(LaConsulta: detalles)
})
}
}
The details
import UIKit
class DetallesConsulta: NSObject {
var Fecha: String?
var Sucursal: String?
var Suc: String?
var VentaTotal: String?
var NoFolios: Int?
var Piezas: String?
var PzaxTicket: String?
var TicketPromedio: String?
override init(){
}
init(Fecha: String, Sucursal: String, Suc: String, VentaTotal: String, NoFolios: Int, Piezas: String, PzaxTicket: String, TicketPromedio: String){
self.Fecha = Fecha
self.Sucursal = Sucursal
self.Suc = Suc
self.VentaTotal = VentaTotal
self.NoFolios = Int(NoFolios)
self.Piezas = Piezas
self.PzaxTicket = PzaxTicket
self.TicketPromedio = TicketPromedio
}
override var description: String{
return "Fecha: \(Fecha), Sucursal: \(Sucursal), Suc: \(Suc), VentaTotal: \(VentaTotal), NoFolios: \(NoFolios), Piezas: \(Piezas), PzaxTicket: \(PzaxTicket), TicketPromedio: \(TicketPromedio)"
}
}
JSON Response
[
{
"Fecha": "2022-11-17",
"Sucursal": "SCALPERS PUEBLA",
"Suc": "004",
"Venta_Total": "xxxxxx.xxxxxxxxx",
"N_Folios": 12,
"Piezas": "xx.000",
"PzaxTicket": "x.x",
"TicketPromedio": "xxxx.x"
},
{
"Fecha": "2022-11-17",
"Sucursal": "SCALPERS SATELITE",
"Suc": "005",
"Venta_Total": "xxxxx.xxx",
"N_Folios": xx,
"Piezas": "xx.000",
"PzaxTicket": "x.x",
"TicketPromedio": "xxxxx.xxxx"
},
{
"Fecha": "2022-11-17",
"Sucursal": "SCALPERS OUTLET QUERETARO",
"Suc": "006",
"Venta_Total": "xxx.xxxxxxxxxx",
"N_Folios": 4,
"Piezas": "6.000",
"PzaxTicket": "1.5",
"TicketPromedio": "1419.5"
},
{
"Fecha": "2022-11-17",
"Sucursal": "SCALPERS ONLINE",
"Suc": "xxxx",
"Venta_Total": "xxxxx.xxxxxxx",
"N_Folios": 15,
"Piezas": "45.000",
"PzaxTicket": "3.0",
"TicketPromedio": "1930.5"
}
]
I hope you can help me.
Thank you.
I downloaded the data from the json and would like to have it displayed in a grid table with this pod.
Your code is too complicated and too objective-c-ish. Never use NSArray/NSDictionary in Swift (except in a few rare CoreFoundation APIs)
To decode the data use Decodable. This is just a small part of the JSON as your class and the hard-coded data are quite different
let jsonString = """
[{"Sucursal":"Hamleys", "Venta_Total":"$1", "Piezas":"10"},
{"Sucursal":"Bobby Brown", "Venta_Total":"$1", "Piezas":"20"}]
"""
Create a struct conforming to Decodable and add CodingKeys to get rid of the capitalized keys. Maybe it's even possible with the .convertFromSnakeCase strategy
struct DetallesConsulta: Decodable {
var sucursal: String
var ventaTotal: String
var piezas: String
private enum CodingKeys: String, CodingKey {
case sucursal = "Sucursal", ventaTotal = "Venta_Total", piezas = "Piezas"
}
}
Then decode the data and to get arrays of the properties map the data.
do {
let result = try JSONDecoder().decode([DetallesConsulta].self, from: Data(jsonString.utf8))
let sucursales = result.map(\.sucursal)
let vtaTotal = result.map(\.ventaTotal)
let piezas = result.map(\.piezas)
print(sucursales, vtaTotal, piezas)
} catch {
print(error)
}
I transfer data from the sharing extension to my main application with UserDefaults and open the application (goToApp()) after hitting the "post" button. However, the view of my app is not redrawn and the text remains the same "Share Extension Example". Here's how I'm trying to do it:
class ShareViewController: SLComposeServiceViewController {
private var textString: String?
override func isContentValid() -> Bool {
if let currentMessage = contentText {
self.textString = currentMessage
}
return true
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didSelectPost() {
UserDefaults.standard.set(self.textString!, forKey: "text")
gotoApp()
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
func gotoApp() {
guard let url = URL(string: "example://") else { return }
let selectorOpenURL = sel_registerName("openURL:")
var responder: UIResponder? = self
while responder != nil {
if responder?.responds(to: selectorOpenURL) == true {
responder?.perform(selectorOpenURL, with: url)
}
responder = responder?.next
}
}
}
And the project to which I am trying to transfer data:
class ViewController: UIViewController {
private let mainVStack = UIStackView()
private let backgroundView = UIImageView()
private let titleLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureMainStack()
configureTitleLabel()
}
}
// MARK: - UI Elements
private extension ViewController {
func configureMainStack() {
mainVStack.distribution = .fillProportionally
mainVStack.embed(asSubviewTo: view, inset: 40)
}
func configureTitleLabel() {
titleLabel.textAlignment = .center
titleLabel.textColor = .blue
if let text = UserDefaults.object(forKey: "text") as? String {
titleLabel.text = text
} else {
titleLabel.text = "Share Extension Example"
}
let titleContainerView = UIView()
titleLabel.embedIn(titleContainerView, hInset: 0, vInset: 100)
mainVStack.addArrangedSubview(titleContainerView)
}
}
I have created a pickerView to pick value into custom textField bar on top of the ViewController to filter data values in UITableView. As I have a nested type of JSON so couldn't properly get how to use filter for it.
I want to implement textField as a search bar with TableView. screenshot attached.
Value which I need to filter is Parkings.Address -> textField
textFieldDidEndEditing function added for text search.
Model:
struct JSONDB: Codable {
var ParkingInfoList: [`Parkings`]
}
struct Parkings: Codable {
var Id: String
var Name: String
var Tel: String
var CarTotal: String
var CarRemaining: String
var Address: String
var ServiceTime: String
var ChargeInfo: String
var ParkinfInfo: String?
var Lat: String
var Lng: String
}
struct JSONDB2: Codable {
var ParkingCityList: [City]
}
struct City: Codable {
var CityCode: String
var CityChtName: String
var CityArea: [String]
}
JSON Data:
{
"ParkingInfoList": [
{
"Id": "K82",
"Name": "瑞湖停車場",
"Tel": "0226573430",
"Address": "文德段5小段297地號;民權東路6段15巷50號空地",
"CarTotal": "46",
"CarRemaining": "暫時無提供資訊",
"MotorTotal": "暫時無提供資訊",
"MotorRemaining": "暫時無提供資訊",
"ServiceTime": "24小時",
"ChargeInfo": "計次:50元/次,(每次以2.5小時為限)。月租:3,000元/月。",
"ParkingInfo": "一般平面式小型車46格(含身心障礙停車位2格)。",
"City": "TPE",
"Area": "內湖區",
"Lat": "25.06854351",
"Lng": "121.5769806",
"SourceUpdateTime": "2020-09-24T00:00:00"
},
ViewController Code:
import UIKit
class SelectedTableViewController: UITableViewController, UIPickerViewDelegate, UIPickerViewDataSource,UITextFieldDelegate {
#IBOutlet weak var myTextfield: UITextField!
let myPickerView = UIPickerView()
var selectedArea = ""
var loadingData = [City]()
var parkingData = [Parkings]()
var okData : Parkings?
var searchActive = false
var arrfilter = [Parkings]()
let apiAddress = "https://lifeinfo.megatime.com.tw/lifeInfo/QueryParkingCityList.ashx"
let urlSession = URLSession(configuration: .default)
override func viewDidLoad() {
super.viewDidLoad()
self.myPickerView.delegate = self
self.myPickerView.dataSource = self
self.myTextfield.delegate = self
downloadInfo(withAddress: apiAddress)
myTextfield.inputView = myPickerView
myPickerView.showsSelectionIndicator = true
}
func downloadInfo(withAddress webAddress: String ){
if let url = URL(string: webAddress){
let task = urlSession.dataTask(with: url) { (data, response, error) in
if error != nil{
let errorcode = (error! as NSError).code
if errorcode == -1009{
print("No Internet Connection")
}else{
print("Something Wrong")
}
return
}
if let loadedData = data{
print("Got Data")
do{
let decoder = JSONDecoder()
let JSONdb = try decoder.decode(JSONDB2.self, from: loadedData)
print("JSONDB2 OK")
self.loadingData = JSONdb.ParkingCityList
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print(error)
}
}
}
task.resume()
}
}
func initPickerView(touchAt sender:UITextField){
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
toolBar.tintColor = .systemBlue
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: "check", style: .plain, target: self, action: #selector(submit))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "cancel", style: .plain, target: self, action: #selector(cancel))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
myTextfield.inputAccessoryView = toolBar
myTextfield.inputView = myPickerView
}
#objc func cancel(){
self.myTextfield?.resignFirstResponder()
}
#objc func submit(sender: UIBarButtonItem){
DispatchQueue.main.async { [self] in
self.myTextfield.text = "taipei \(self.selectedArea)"
self.myTextfield?.resignFirstResponder()
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0{
return 1
}
return loadingData[0].CityArea.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0{
return "taipei"
}
let test = loadingData[0].CityArea[row]
// print(test)
return test
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField == self.myTextfield {
myTextfield.isHidden = false
myPickerView.removeFromSuperview()
self.initPickerView(touchAt: textField)
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
myTextfield.text = "臺北市 \(loadingData[0].CityArea[row])"
self.selectedArea = loadingData[0].CityArea[row]
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if myTextfield.text == ""{
return parkingData.count
}else {
myTextfield.text = selectedArea
}
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SelectedTableViewCell", for: indexPath) as! SelectedTableViewCell
let data = parkingData[indexPath.row]
cell.lbRemaining.text = data.CarRemaining
cell.lbName.text = data.Name
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.okData = self.parkingData[indexPath.row]
performSegue(withIdentifier: "DetailSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailSegue"{
let detail = segue.destination as! DetailTableViewController
detail.okData = self.okData
}
}
}
Below is the filter part I already tried but failed:
try 1: predicate way but show error: "Unable to parse the format string "SELF.Address CONTAINTS[C] %#""
try 2: filter way but show error: "Cannot convert value of type 'Parkings' to type 'NSString' in coercion "
func textFieldDidEndEditing(_ textField: UITextField) {
guard let searchText:String = myTextfield.text else {
return}
\\ try 1: predicate way but show error: "Unable to parse the format string \"SELF.Address CONTAINTS[C] %#\""
let predicate:NSPredicate = NSPredicate(format: "SELF.Address CONTAINTS[C] %#", searchText)
let array = (parkingData as NSArray).filtered(using: predicate)
print("array =\(array)")
\\ try 2: filter way but show error: "Cannot convert value of type 'Parkings' to type 'NSString' in coercion "
arrfilter = parkingData.filter({ (test) -> Bool in
let tmp: NSString = test as NSString
let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
if(arrfilter.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tableView.reloadData()
}
The final present should shown like this
I'm currently trying to develop a prototype for a quiz application.
The questions for the quiz are read out of a JSON file and the answers are generated within the program. Those two parts are then matched to each other within a Mediator class.
Displaying the question in my ViewController works perfectly fine for the first question. When trying to retrieve the second question the array that stores the question in the Mediator class is empty. That obviously is the case, because I'm re-entering the Mediator after going to my ViewController.
How can I store the data more efficiently?
If you need more information, please let me know. I'm really grateful for every suggestion I can get. I'm totally stuck at right now!
ViewController:
[...]
override func viewDidLoad() {
super.viewDidLoad()
setup(categoryType)
navigationBar.title = barTitle
QAMatcher.delegate = self
QAMatcher.getCategory(categoryType)
}
#objc func didChooseAnswer(_ sender: UIButton){
QAMatcher.nextQuestion()
updateUI()
}
func updateUI(){
if let label = questionLabel {
label.text = QAMatcher.getQuestion()
}
if let type = AnswerType(rawValue: QAMatcher.getAnswerType()) {
addAnswerSection(type)
}
}
func addAnswerSection(_ type: AnswerType) {
if let stackView = quizStackView, let answerSection = uiBuilder.getAnswerSection(answerType: type) {
stackView.addArrangedSubview(answerSection)
}
}
[...]
Mediator Class:
import Foundation
protocol Mediator {
func sendRequest (_ request: Request, sender: Sender)
}
protocol MediatorDelegate {
func didUpdate(mediator: QuestionAnswerMediator, _ array: [QuestionData])
}
enum Sender {
case answer
case question
}
class QuestionAnswerMediator: Mediator {
var delegate: MediatorDelegate?
var questionArray = [QuestionData]()
var answerArray = [String]()
var request = Request()
var questionNum = 0
func getCategory(_ category: CategoryType) {
request.categoryType = category
matchQuestionAndAnswers()
}
func sendRequest (_ request: Request, sender: Sender){
if sender == .question {
let array = QuestionManager.shared.send(category: request.categoryType!)
questionArray.append(contentsOf: array)
}
else if sender == .answer {
let array = AnswerManager.shared.send(request: request)
if array?.isEmpty == false {
answerArray = []
answerArray.append(contentsOf: array ?? ["default"])
}
}
}
func fetchAnswers(for type: String, question: String) {
request.answerType = AnswerType(rawValue: type)
request.question = question
sendRequest(request, sender: .answer)
}
func fetchQuestions (for category: CategoryType){
request.categoryType = category
sendRequest(request, sender: .question)
}
func matchQuestionAndAnswers(){
var i = 0
fetchQuestions(for: request.categoryType!)
for question in questionArray {
fetchAnswers(for: question.answerType, question: question.question)
if answerArray.isEmpty != true {
questionArray[i].answers = answerArray
}
i += 1
}
self.delegate?.didUpdate(mediator: self, questionArray)
}
func getQuestion() -> String {
return questionArray[questionNum].question
}
func getAnswers() -> [String] {
return questionArray[questionNum].answers!
}
func getAnswerType() -> String {
return questionArray[questionNum].answerType
}
func nextQuestion () {
if questionNum + 1 < questionArray.count {
questionNum += 1
}
else {
questionNum = 0
}
}
}
ok, that was hard ;) i had to create my own project file, because yours was still missing. After doing that i tried to compile and run...but you did not fill the assets so it crashed. After faking your assets...it runs. ;)
You already analyzed your problem correctly. You should never create a viewcontroller mutliple times if you just call him once. So i deleted this and you now only have one instance.
i routed the "didchooseAnswer" through your classes...but you still have some work to do: i had to give a frame to your view class, so fill that frame you need, i don't know what frame you need.
I just corrected it for MultipleChoiceView...you have to do it for the other views as well like PolarView etc...
i hope i have everything copied what i changed, if not, just tell me. but maybe then you should give me rights on your github project so that i can commit it there...
Quizviewcontroller:
import UIKit
import CoreLocation
import os
class QuizViewController: UIViewController {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var navigationBar: UINavigationItem!
#IBOutlet var mainView: UIView!
#IBOutlet weak var quizStackView: UIStackView!
var barTitle: String?
//variables for location services
var locationManager = CLLocationManager()
var locationData: LocationModel?
//variables for communication with Mediator
var QAMatcher = QuestionAnswerMediator()
var questions : [QuestionData]?
var categoryType: CategoryType!
var timer = Timer()
//Change UI depending on answer type
var uiBuilder = AnswerViewBuilder()
override func viewDidLoad() {
super.viewDidLoad()
setup(categoryType)
navigationBar.title = barTitle
QAMatcher.delegate = self
QAMatcher.getCategory(categoryType)
}
#objc func didChooseAnswer(_ sender: UIButton){
QAMatcher.nextQuestion()
updateUI()
}
}
//MARK: - Setup & updating UI
extension QuizViewController: MediatorDelegate {
func didUpdate(mediator: QuestionAnswerMediator, _: [QuestionData]) {
self.updateUI()
}
func setup(_ category: CategoryType?) {
switch category {
case .shortterm:
print("No function yet")
case .longterm:
print("No function yet")
case .problemsolving:
print("No function yet")
case .orientation:
locationManager.delegate = self
checkLocationServiceSupport()
locationManager.requestWhenInUseAuthorization()
gecodeCurrentLocation()
default:
let message: StaticString = M.Errors.invalidCategoryError
os_log(message, log: OSLog.default, type: .error)
}
}
func updateUI(){
if let label = questionLabel {
label.text = QAMatcher.getQuestion()
}
if let type = AnswerType(rawValue: QAMatcher.getAnswerType()) {
addAnswerSection(type)
}
}
func addAnswerSection(_ type: AnswerType) {
if let stackView = quizStackView, let answerSection = uiBuilder.getAnswerSection(answerType: type, didChooseAnswer: self.didChooseAnswer(_:)) {
stackView.addArrangedSubview(answerSection)
}
}
}
//MARK: - CLLocationManagerDelegate
extension QuizViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
let message: StaticString = M.Errors.locationDetectionError
os_log(message, log: OSLog.default, type: .error)
}
func checkLocationServiceSupport () {
if CLLocationManager.significantLocationChangeMonitoringAvailable() != true {
let alert = UIAlertController(title: M.Alters.locationAlertTitle, message: M.Alters.locationAlert, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
NSLog("The user acknowledge that location services are not available.")
}))
self.present(alert, animated: true, completion: nil)
self.dismiss(animated: true, completion: nil)
}
}
func gecodeCurrentLocation() {
locationManager.requestLocation()
if let lastLocation = self.locationManager.location {
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(lastLocation) { (placemarks, error) in
if error == nil {
if let placemark = placemarks?.first {
let city = placemark.locality!
let country = placemark.country!
self.locationData = LocationModel(city: city,country: country)
}
}
else {
let message: StaticString = M.Errors.locationDecodingError
os_log(message, log: OSLog.default, type: .error)
}
}
}
}
}
//MARK: - UITextFieldDelegate
//extension CategoryViewController: UITextFieldDelegate {
//
// func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
// if textField.text != "" {
// return true
// }
// else {
// textField.placeholder = "Enter your answer here"
// return false
// }
// }
//
// func textFieldDidEndEditing(_ textField: UITextField) {
// }
//
// func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// textField.endEditing(true)
// return true
// }
//}
MulitpleChoiceView
import UIKit
class MultipleChoiceView: UIStackView {
var button1 = UIButton()
var button2 = UIButton()
var button3 = UIButton()
var didChooseAnswer : ((UIButton)->())?
init(frame: CGRect, didChooseAnswer: #escaping (UIButton)->()) {
super.init(frame: frame)
self.didChooseAnswer = didChooseAnswer
self.addAnswerView()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addAnswerView() {
setupStackView()
costumeButtons()
}
func setupStackView() {
self.alignment = .fill
self.distribution = .fillEqually
self.spacing = 10
self.axis = .vertical
}
func costumeButtons() {
let buttons = [button1 , button2, button3]
let dimensions = CGRect(x: 0, y: 0, width: 120, height: 20)
let color = #colorLiteral(red: 0.7294117647, green: 0.7450980392, blue: 1, alpha: 1)
for button in buttons {
button.frame = dimensions
button.backgroundColor = color
button.layer.cornerRadius = button.frame.size.height / 4
button.isUserInteractionEnabled = true
button.addTarget(self, action: M.Selector.buttonAction, for: .touchUpInside)
self.addArrangedSubview(button)
}
}
#objc func didChooseAnswer(_ sender: UIButton) {
if let didChooseAnswer = didChooseAnswer {
didChooseAnswer(sender)
}
}
}
AnswerViewBuilder
import UIKit
class AnswerViewBuilder {
func getAnswerSection(answerType: AnswerType, didChooseAnswer: #escaping (UIButton)->()) -> UIView?{
switch (answerType) {
case .multipleChoice:
return MultipleChoiceView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), didChooseAnswer: didChooseAnswer)
case .textField:
return TextFieldView()
case .polarQuestion:
return PolarQuestionView()
case .ranking:
return MultipleChoiceView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), didChooseAnswer: didChooseAnswer)
default:
print("Answer section could not be created.")
return nil
}
}
}
How can I update or insert a row in a tableview without reloading all the data?
In the ClientsViewController a list of clients is shown alphabetically and separated by sections (first letter of the client`s name).
When I update a client, the tableview shows 2 entries (old and new one) of the same client. When I try to add a client, it crashes.
I think the problem is with indexing.
class ClientsViewController: UITableViewController {
var sortedFirstLetters: [String] = []
var sections: [[Client]] = [[]]
var tableArray = [Client]()
var client: Client?
var refresher: UIRefreshControl!
#IBOutlet var noClientsView: UIView!
#IBAction func unwindToClients(sender: UIStoryboardSegue) {
if let sourceViewController = sender.source as? ClientViewController, let client = sourceViewController.client {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing client.
tableArray[selectedIndexPath.row] = client
tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
}
else {
// Add a client.
let newIndexPath = IndexPath(row: tableArray.count, section: 0)
tableArray.append(client)
tableView.insertRows(at: [newIndexPath], with: .automatic)
}
let firstLetters = self.tableArray.map { $0.nameFirstLetter }
let uniqueFirstLetters = Array(Set(firstLetters))
self.sortedFirstLetters = uniqueFirstLetters.sorted()
self.sections = self.sortedFirstLetters.map { firstLetter in
return self.tableArray
.filter { $0.nameFirstLetter == firstLetter }
.sorted { $0.name < $1.name }
}
// DispatchQueue.main.async {
// self.tableView.reloadData()
// }
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondScene = segue.destination as! ClientViewController
if segue.identifier == "ShowDetail", let indexPath = self.tableView.indexPathForSelectedRow {
let currentPhoto = sections[indexPath.section][indexPath.row]
secondScene.client = currentPhoto
}
else if segue.identifier == "AddItem" {
print("add")
}
else {
fatalError("The selected cell is not being displayed by the table")
}
}
#objc func handleRefresh(_ refreshControl: UIRefreshControl) {
getClients()
refreshControl.endRefreshing()
}
}
extension ClientsViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl?.addTarget(self, action: #selector(ClientsViewController.handleRefresh(_:)), for: UIControlEvents.valueChanged)
tableView.backgroundView = noClientsView
getClients() //for only the 1st time ==> when view is created ==> ok ish
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
getClients() // not a good idea to make a request to the server everytime the view appears on the screen.
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if(self.tableArray.count > 0) {
return sortedFirstLetters[section]
}
else {
return ""
}
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
print(sortedFirstLetters)
return sortedFirstLetters
}
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let name = sections[indexPath.section][indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ClientCell", for: indexPath)
cell.textLabel?.text = name.name
cell.detailTextLabel?.text = name.city + " - " + name.province
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(sections[section].count > 0) {
tableView.backgroundView = nil
}
return sections[section].count
}
func getClients() {
makeRequest(endpoint: "api/clients/all",
parameters: [:],
completionHandler: { (container : ApiContainer<Client>?, error : Error?) in
if let error = error {
print("error calling POST on /getClients")
print(error)
return
}
self.tableArray = (container?.result)!
self.prepareData()
DispatchQueue.main.async {
self.tableView.reloadData()
}
} )
}
//sorts and makes the index
func prepareData() {
let firstLetters = self.tableArray.map { $0.nameFirstLetter }
let uniqueFirstLetters = Array(Set(firstLetters))
self.sortedFirstLetters = uniqueFirstLetters.sorted()
self.sections = self.sortedFirstLetters.map { firstLetter in
return self.tableArray
.filter { $0.nameFirstLetter == firstLetter }
.sorted { $0.name < $1.name }
}
}
}
Bellow is ClientViewController and Client struct.
class ClientViewController: UITableViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var addressTextField: UITextField!
#IBOutlet weak var cityTextField: UITextField!
#IBOutlet weak var provinceTextField: UITextField!
#IBOutlet weak var postalCodeTextField: UITextField!
#IBOutlet weak var contactsLabel: UILabel!
let numberOfRowsAtSection: [Int] = [4, 2]
var client: Client?
var selectedProvince: String?
override func viewWillAppear(_ animated: Bool) {
self.title = "New"
if (client?.client_id) != nil {
self.title = "Edit"
nameTextField.text = client?.name
provinceTextField.text = client?.province
cityTextField.text = client?.city
addressTextField.text = client?.address
postalCodeTextField.text = client?.postal_code
selectedProvince = client?.province
}
}
#objc func save(sender: UIButton!) {
let name = nameTextField.text ?? ""
let address = addressTextField.text ?? ""
let city = cityTextField.text ?? ""
let province = selectedProvince ?? ""
let postal_code = postalCodeTextField.text ?? ""
var endPoint: String
if (client?.client_id) != nil {
endPoint = "api/clients/update"
} else {
endPoint = "api/clients/add"
}
client = Client(name:name, client_id: client?.client_id, postal_code: postal_code, province: province, city: city, address: address)
let requestBody = makeJSONData(client)
makeRequestPost(endpoint: endPoint,
requestType: "POST",
requestBody: requestBody,
view: view,
completionHandler: { (response : ApiContainer<Client>?, error : Error?) in
if let error = error {
print("error calling POST on /todos")
print(error)
return
}
let b = (response?.meta)!
let a = (response?.result[0])
let client_id = a?.client_id
self.client?.client_id = client_id
if(b.sucess == "yes") {
//change message and use the custom func like on error.
let alert = UIAlertController(title: "Success!", message: "All good", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {
(_)in
self.performSegue(withIdentifier: "unwindToClients", sender: self)
})
alert.addAction(OKAction)
DispatchQueue.main.async(execute: {
self.present(alert, animated: true, completion: nil)
})
}
else
{
self.showAlert(title: "Error", message: "Error Creating Client")
//return
}
} )
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.sectionHeaderHeight = 50.0;
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .plain, target: self, action: #selector(save))
let thePicker = UIPickerView()
provinceTextField.inputView = thePicker
thePicker.delegate = self
// ToolBar
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor(red: 92/255, green: 216/255, blue: 255/255, alpha: 1)
toolBar.sizeToFit()
// Adding Button ToolBar
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ClientDetailViewController.doneClick))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(ClientDetailViewController.cancelClick))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
provinceTextField.inputAccessoryView = toolBar
}
#objc func doneClick() {
provinceTextField.resignFirstResponder()
}
#objc func cancelClick() {
provinceTextField.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var rows: Int = 0
if section < numberOfRowsAtSection.count {
rows = numberOfRowsAtSection[section]
}
return rows
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = "Client"
navigationItem.backBarButtonItem = backItem
if segue.identifier == "unwindToClients",
let destination = segue.destination as? ClientsViewController
{
destination.client = client
}
if segue.identifier == "showContacts",
let destination = segue.destination as? ContactsViewController
{
destination.client = client
}
}
// MARK: - Picker view
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView( _ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return provinces.count
}
func pickerView( _ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return provinces[row].name
}
func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
provinceTextField.text = provinces[row].name
}
}
struct Client: Codable {
var client_id: Int!
let name: String!
let postal_code: String!
let province: String!
let city: String!
let address: String!
init(name: String, client_id: Int! = nil, postal_code: String, province: String, city: String, address: String) {
self.client_id = client_id
self.name = name
self.postal_code = postal_code
self.province = province
self.city = city
self.address = address
}
var nameFirstLetter: String {
return String(self.name[self.name.startIndex]).uppercased()
}
}
Append the items in datasource at index where you want to insert row in table. than follow steps 2,3,4.
Call method tbl.beginupdate
call insertRowsAtIndexPaths method of table view
Call tbl.endupdate
you can update tableView rows using this..
self.tableView.reloadRows(at: [indexPath!], with: .top)