I have a problem with a swipe gesture. I insert the NSUserdefaults function, but it doesn't work. Whenever I swipe, the value (you can see 90 at the pic) is always missing whenever I swipe it back.
The code that I insert NSUserdefaults looks like this:
This is the table controller, which shows the JSON data:
struct JSONActivity
{
static var jsondata = ""
}
class TableControllerActivities: UITableViewController {
var items = NSMutableArray()
var TableData:Array< String > = Array < String >()
var json:String = ""
#IBOutlet var myTableView: UITableView!
var arrayOfMenu: [Activity] = [Activity]()
#IBAction func setting(sender: AnyObject) {
self.performSegueWithIdentifier("SettingView", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.setUpMenu()
self.myTableView.delegate = self
self.myTableView.dataSource = self
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfMenu.count //hitung banyak data pada array
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//fungsi agar json dapat membaca tiap row pada storyboard
var shortDate: String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM"
return dateFormatter.stringFromDate(NSDate())
}
let cell: CustomCellActivity = tableView.dequeueReusableCellWithIdentifier("cell") as! CustomCellActivity
let menu = arrayOfMenu[indexPath.row]
cell.setCell(menu.type, rightlabeltext: menu.unit, imagename: menu.image)
//memasukkan data ke json, misal textbox isi 3 maka akan diwrite ke json 3
var data = Activitiesdata(type: menu.type, amount: String(cell.value).toInt()!)
var json = JSONSerializer.toJson(data)
JSONActivity.jsondata = json
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func do_table_refresh()//mengapdet / merefresh data
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
func setUpMenu() //membaca json pada setiap arraynya
{
var json: JSON = JSON (data: NSData())
let frame:CGRect = CGRect(x: 110, y: 300, width: view.frame.width, height: 700)
self.tableView.frame = frame
DataManager.getactivityDataFromFileWithSuccess{ (data) -> Void in
json = JSON(data: data)
let results = json["results"]
for (index: String, subJson: JSON) in results {
}
for (var i = 0; i < json["Activity"].count; i++) {
if let type = json["Activity"][i]["type"].string {
//println("Tipe : \(type)")
if let icon: AnyObject = json["Activity"][i]["icon"].string {
self.items.addObject(icon)
if let unit_id = json["Activity"][i]["unit_id"].string {
//println("Logo : \(unit_id)")
dispatch_async(dispatch_get_main_queue(), {self.tableView!.reloadData()})
var menu = Activity(type: type, unit: unit_id, image: icon as! String)
self.arrayOfMenu.append(menu)
self.TableData.append(type + unit_id )
self.do_table_refresh()
}
}
}
}
}
}
}
And this is the cell controller, where the value is incremented:
struct Activitymenu
{
static var dataact:Array<String> = Array <String>()
static var quantity = ""
}
class CustomCellActivity: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var leftlabel: UILabel!
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var rightlabel: UILabel!
#IBOutlet weak var qtytext: UITextField!
#IBOutlet weak var decrease: UIImageView!
var value = 0
var checks:Bool = false
var dx = 0
override func awakeFromNib() {
super.awakeFromNib()
self.myImageView.userInteractionEnabled = true
self.decrease.userInteractionEnabled = true
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
qtytext.resignFirstResponder()
self.endEditing(true)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch: UITouch? = touches.first as? UITouch
if(touch?.view == myImageView)
{
value += 30
qtytext.text = String(value)
println(qtytext.text)
}
if(touch?.view == decrease)
{
if(value >= 30)
{
value -= 30;
println(qtytext.text)
}
}
qtytext.resignFirstResponder()//respon pada editing textbox
self.endEditing(true)
qtytext.delegate = self
qtytext.text = String(value)
let myquantity = qtytext.text
NSUserDefaults.standardUserDefaults().setObject(myquantity, forKey: "SavedStringKey")
NSUserDefaults.standardUserDefaults().synchronize()
let stringKey = NSUserDefaults.standardUserDefaults()
qtytext.text = stringKey.stringForKey("SavedStringKey")
var data = Activitiesdata(type: leftlabel.text!, amount: qtytext.text.toInt()!)
var temp:Activitiesdata
temp = data
var idx = 0
if(temp.amount-30 > 0) {
temp.amount -= 30
}
data = Activitiesdata(type: leftlabel.text!, amount: qtytext.text.toInt()!)
var json = JSONSerializer.toJson(data)
var tempJson = JSONSerializer.toJson(temp)
for(var i = 0; i < Activitymenu.dataact.count; i++){
if(Activitymenu.dataact[i] == tempJson){
self.checks = true
self.dx = i
}
}
if(!self.checks) {
Activitymenu.dataact.append(json)
}
else{
Activitymenu.dataact[self.dx] = json
}
}
func setCell(leftlabeltext: String, rightlabeltext: String, imagename: String)
{
self.leftlabel.text = leftlabeltext
self.rightlabel.text = rightlabeltext
self.myImageView.image = UIImage(named: imagename)
}
}
I think, the value is still there, but it not shown, why is that?
myquantity, value and qty text have the same output of 90..3.
Related
first I want to tell you what's my goal:
It should be possible for my app users to tap the + or - Stepper in each ProductTableViewCell to add or remove products to/from Cart.
In the NewOrderViewController where the productTableView is embedded there should be a label for showing the user how many products are in Cart at all. I named it totalProductCountLabel.
Also there should be a label named totalProductPriceLabel, to show the price for all products in Cart. The Cart should be updated every time the user taps the stepper inside a cell, and when the product.counter value is 0, then the product should be automatically removed from Cart.
Yesterday I've had a solution which works perfect:
ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CartSelection {
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
#IBOutlet weak var testTableview: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
var productArray = [Product]()
var cartDictionary = [String: Product]()
override func viewDidLoad() {
super.viewDidLoad()
testTableview.delegate = self
testTableview.dataSource = self
testTableview.allowsSelection = false
productArray.append(Product(name: "Bananen", count: 0, price: 1.09, uuid: UUID().uuidString))
productArray.append(Product(name: "Äpfel", count: 0, price: 0.81, uuid: UUID().uuidString))
productArray.append(Product(name: "Kirschen", count: 0, price: 6.34, uuid: UUID().uuidString))
productArray.append(Product(name: "Tomaten", count: 0, price: 2.68, uuid: UUID().uuidString))
productArray.append(Product(name: "Weintrauben", count: 0, price: 1.48, uuid: UUID().uuidString))
productArray.append(Product(name: "Schokolade", count: 0, price: 0.67, uuid: UUID().uuidString))
testTableview.reloadData()
timerEnabled = true
timerCount = 0
self.totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
self.totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timerEnabled = false
timerCount = 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
timerEnabled = false
timerCount = 5
}
func startTimer() {
_ = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
if self.timerEnabled != false && self.timerCount < 4 {
self.testTableview.reloadData()
print("Die Produktliste wurde aktualisiert!")
self.timerCount += 1
} else {
timer.invalidate()
self.timerEnabled = true
self.timerCount = 0
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TestTableViewCell
cell.product = productArray[indexPath.row]
cell.productNameLabel.text = "\(cell.product.name)"
cell.productPriceLabel.text = "\(cell.product.price)" + " € / kg"
cell.productCountLabel.text = "\(cell.product.count)"
cell.cartSelectionDelegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 188
}
func addProductToCart(product: Product, uuid: String) {
timerEnabled = false
cartDictionary[uuid] = product
if cartDictionary[uuid]?.count == 0 {
cartDictionary.removeValue(forKey: uuid)
}
calculateTotal()
}
func calculateTotal() {
var totalProductCount = 0
var totalProductPrice = 0.00
for (_,value) in cartDictionary {
totalProductCount += value.count
totalProductPrice += value.totalPrice
}
self.totalProductCountLabel.text = "Anzahl Produkte: \(totalProductCount) Stück"
self.totalProductPriceLabel.text = "Preis Produkte: \(String(format: "%5.2f", totalProductPrice)) €"
self.totalProductCount = totalProductCount
if cartDictionary.isEmpty {
print("Der Einkaufswagen ist leer")
timerEnabled = true
timerCount = 0
startTimer()
}
}
#IBAction func orderButtonTapped(_ sender: UIButton) {
if totalProductCount != 0 {
showOrderConfirmation()
var priceLabel = 0.00
print("Im Einkaufwagen sind folgende Produkte:")
for (key,value) in cartDictionary {
priceLabel += value.totalPrice
print("Produkt: \(value.name) --> \(value.count) __ Produktkennung: \(key)")
}
print("Gesamtpreis: \(priceLabel)")
}
}
func showOrderConfirmation() {
let alert = UIAlertController(title: "Bestellung aufgeben?", message: nil, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Bestellung aufgeben", style: .default)
let cancelAction = UIAlertAction(title: "Bestellung bearbeiten", style: .destructive)
alert.addAction(okayAction)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
}
Product Model
import UIKit
struct Product {
var name = "Produkt"
var count = 0
var price = 0.00
var totalPrice: Double {
return Double((count)) * (price)
}
var uuid = "Example: 20EE8409-230C-4E69-B366-C2EEE03998AF"
}
protocol CartSelection {
func addProductToCart(product : Product, uuid : String)
}
TableViewCell
import UIKit
class TestTableViewCell: UITableViewCell {
var cartSelectionDelegate: CartSelection?
#IBOutlet weak var productCountLabel: UILabel!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func cellTrashButtonTapped(_ sender: UIButton) {
resetCell()
}
#IBAction func changeProductCountStepper(_ sender: UIStepper) {
productCountLabel.text = Int(sender.value).description
product.count = Int(sender.value)
let totalPriceForProduct = Double(product.count) * product.price
totalProductPriceLabel.text = "Produktgesamtpreis: \(String(format: "%5.2f", totalPriceForProduct)) €"
updateChanges()
}
func updateChanges() {
cartSelectionDelegate?.addProductToCart(product: product, uuid: product.uuid)
}
func resetCell() {
productCountLabel.text = "0"
product.count = 0
totalProductPriceLabel.text = "Produktgesamtpreis: 0.00 €"
stepper.value = 0
updateChanges()
}
override func awakeFromNib() {
super.awakeFromNib()
stepper.autorepeat = true
}
var product : Product!
var productIndex = 0
}
Now my products are stored in Firebase Firestore, so I don't need the append method anymore and using a query instead.
All works as before, my products are shown in the table.
First Problem:
My Outlets from the ViewController are all nil, when pressing the stepper, so I can't see my label counting anymore. (The one in the ViewController), the labels in the cell are working.
Second Problem:
In the first code I am using a dictionary to store all the products in it ("cartDictionary").
This works in the second code, too. But only for one product. The counter in the dictionary is updating if I only tap one cells stepper, but if I tap on another cells stepper, the whole dictionary is empty and it starts with the other product again.
I can't find a solution for this problem, I know the problem is something with my ViewController is not initialized when using my outlets, but if I initialize it my dataSource crashes.
It would be very nice if there's someone helping me, because I can't go on working the last days.
Thank you very much!
My code that's not working:
Product Model
import UIKit
import FirebaseFirestore
protocol CartSelection {
func addProductToCart(product : Product, uuid : String)
}
struct Product {
var documentID: String
var shopID: String
var productName: String
var productPrice: Double
var counter: Int
var uuid: String
var totalPrice: Double {
return Double((counter)) * (productPrice)
}
}
// MARK: - Firestore interoperability
extension Product: DocumentSerializable {
/// Initializes a shop with a documentID auto-generated by Firestore.
init(shopID: String,
productName: String,
productPrice: Double,
counter: Int,
uuid: String) {
let document = Firestore.firestore().shops.document()
self.init(documentID: document.documentID,
shopID: shopID,
productName: productName,
productPrice: productPrice,
counter: counter,
uuid: uuid)
}
/// Initializes a shop from a documentID and some data, from Firestore.
private init?(documentID: String, dictionary: [String: Any]) {
guard let shopID = dictionary["shopID"] as? String,
let productName = dictionary["productName"] as? String,
let productPrice = dictionary["productPrice"] as? Double,
let counter = dictionary["counter"] as? Int,
let uuid = dictionary["uuid"] as? String else { return nil }
self.init(documentID: documentID,
shopID: shopID,
productName: productName,
productPrice: productPrice,
counter: counter,
uuid: uuid)
}
init?(document: QueryDocumentSnapshot) {
self.init(documentID: document.documentID, dictionary: document.data())
}
init?(document: DocumentSnapshot) {
guard let data = document.data() else { return nil }
self.init(documentID: document.documentID, dictionary: data)
}
/// The dictionary representation of the restaurant for uploading to Firestore.
var documentData: [String: Any] {
return [
"shopID": shopID,
"productName": productName,
"productPrice": productPrice,
"counter": counter,
"uuid": uuid
]
}
}
Product TableViewCell
import UIKit
import FirebaseFirestore
class ProductTableViewCell: UITableViewCell {
var cartSelectionDelegate: CartSelection?
#IBOutlet weak var productCountLabel: UILabel!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func cellTrashButtonTapped(_ sender: UIButton) {
resetCell()
}
#IBAction func changeProductCountStepper(_ sender: UIStepper) {
productCountLabel.text = Int(sender.value).description
product.counter = Int(sender.value)
let totalPriceForProduct = Double(product.counter) * product.productPrice
totalProductPriceLabel.text = "Produktgesamtpreis: \(String(format: "%5.2f", totalPriceForProduct)) €"
updateChanges()
}
func updateChanges() {
cartSelectionDelegate?.addProductToCart(product: product, uuid: product.uuid)
}
func resetCell() {
productCountLabel.text = "0"
product.counter = 0
totalProductPriceLabel.text = "Produktgesamtpreis: 0.00 €"
stepper.value = 0
updateChanges()
}
override func awakeFromNib() {
super.awakeFromNib()
stepper.autorepeat = true
}
var product : Product!
var productIndex = 0
}
Product TableViewDataSource
import UIKit
import FirebaseFirestore
#objc class ProductTableViewDataSource: NSObject, UITableViewDataSource {
private let products: LocalCollection<Product>
var sectionTitle: String?
public init(products: LocalCollection<Product>) {
self.products = products
}
public convenience init(query: Query, updateHandler: #escaping ([DocumentChange]) -> ()) {
let collection = LocalCollection<Product>(query: query, updateHandler: updateHandler)
self.init(products: collection)
}
public func startUpdates() {
products.listen()
}
public func stopUpdates() {
products.stopListening()
}
subscript(index: Int) -> Product {
return products[index]
}
public var count: Int {
return products.count
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitle
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.TableView.productCell, for: indexPath) as! ProductTableViewCell
cell.product = products[indexPath.row]
cell.productNameLabel.text = "\(cell.product.productName)"
cell.productPriceLabel.text = "\(cell.product.productPrice)" + " € / kg"
cell.productCountLabel.text = "\(cell.product.counter)"
cell.cartSelectionDelegate = NewOrderViewController()
return cell
}
}
NewOrderViewController
import UIKit
import FirebaseFirestore
class NewOrderViewController: UIViewController, UITableViewDelegate, CartSelection {
#IBOutlet var productTableView: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
private var shop: Shop!
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
var cartDictionary = [String: Product]()
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
productTableView.dataSource = dataSource
productTableView.delegate = self
query = baseQuery
productTableView.allowsSelection = false
productTableView.reloadData()
timerEnabled = true
timerCount = 0
totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setNeedsStatusBarAppearanceUpdate()
dataSource.startUpdates()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
dataSource.stopUpdates()
timerEnabled = false
timerCount = 0
}
// MARK: - DataSource and Query
private func dataSourceForQuery(_ query: Query) -> ProductTableViewDataSource {
return ProductTableViewDataSource(query: query) { [unowned self] (changes) in
self.productTableView.reloadData()
}
}
lazy private var dataSource: ProductTableViewDataSource = {
return dataSourceForQuery(baseQuery)
}()
lazy private var baseQuery: Query = {
Firestore.firestore().products.whereField("shopID", isEqualTo: shop.documentID)
}()
fileprivate var query: Query? {
didSet {
dataSource.stopUpdates()
productTableView.dataSource = nil
if let query = query {
dataSource = dataSourceForQuery(query)
productTableView.dataSource = dataSource
dataSource.startUpdates()
}
}
}
// MARK: - Delegate Method
func addProductToCart(product: Product, uuid: String) {
timerEnabled = false
cartDictionary[uuid] = product
if cartDictionary[uuid]?.counter == 0 {
cartDictionary.removeValue(forKey: uuid)
}
calculateTotal()
}
// MARK: - Actions
#IBAction func orderButtonTapped(_ sender: UIButton) {
if totalProductCount != 0 {
showOrderConfirmation()
var priceLabel = 0.00
print("Im Einkaufwagen sind folgende Produkte:")
for (key,value) in cartDictionary {
priceLabel += value.totalPrice
print("Produkt: \(value.productName) --> \(value.counter) __ Produktkennung: \(key)")
}
print("Gesamtpreis: \(priceLabel)")
}
}
// MARK: - Functions
func showOrderConfirmation() {
let alert = UIAlertController(title: "Bestellen?", message: nil, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Bestellung aufgeben", style: .default)
let cancelAction = UIAlertAction(title: "Bestellung bearbeiten", style: .destructive)
alert.addAction(okayAction)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
func calculateTotal() {
var totalProductCount = 0
var totalProductPrice = 0.00
for (_,value) in cartDictionary {
totalProductCount += value.counter
totalProductPrice += value.totalPrice
}
self.totalProductCountLabel.text = "Anzahl Produkte: \(totalProductCount) Stück"
self.totalProductPriceLabel.text = "Preis Produkte: \(String(format: "%5.2f", totalProductPrice)) €"
if cartDictionary.isEmpty {
print("Der Einkaufswagen ist leer")
timerEnabled = true
timerCount = 0
startTimer()
}
}
func startTimer() {
_ = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
if self.timerEnabled != false && self.timerCount < 4 {
self.productTableView.reloadData()
print("Die Produktliste wurde aktualisiert!")
self.timerCount += 1
} else {
timer.invalidate()
self.timerEnabled = true
self.timerCount = 0
}
}
}
// MARK: - TableView Delegate
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 188
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
timerEnabled = false
timerCount = 5
}
// MARK: - Navigation
static func fromStoryboard(_ storyboard: UIStoryboard = UIStoryboard(name: Constants.StoryboardID.main, bundle: nil),
forShop shop: Shop) -> NewOrderViewController {
let controller = storyboard.instantiateViewController(withIdentifier: Constants.StoryboardID.newOrderViewController) as! NewOrderViewController
controller.shop = shop
return controller
}
}
All problems fixed by making a static instance of my NewOrderViewController!
class NewOrderViewController: UIViewController, UITableViewDelegate, CartSelection {
#IBOutlet var productTableView: UITableView!
#IBOutlet weak var totalProductCountLabel: UILabel!
#IBOutlet weak var totalProductPriceLabel: UILabel!
private var shop: Shop!
var totalProductCount = 0
var timerEnabled = true
var timerCount = 0
var cartDictionary = [String: Product]()
static var instance: NewOrderViewController?
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
NewOrderViewController.instance = self
productTableView.dataSource = dataSource
productTableView.delegate = self
query = baseQuery
productTableView.allowsSelection = false
productTableView.reloadData()
timerEnabled = true
timerCount = 0
totalProductCountLabel.text = "Anzahl Produkte: 0 Stück"
totalProductPriceLabel.text = "Preis Produkte: 0.00 €"
}
Good morning, everyone,
I have created a TableView that uses data from a JSON file.
I can put my data in my TableView with Alamofire, but for ease of reference I would like to sort them by section with date.
Because for each date over 15 days there are weather forecasts for each hour.
So ideally I would like a section per day that opens with the click and gives every hour with forecasts.
This is my ViewController:
import UIKit
import Alamofire
import MapKit
class WeatherProController: UIViewController, CLLocationManagerDelegate, UITableViewDataSource,UITableViewDelegate {
private let refreshControl = UIRefreshControl()
var datas = [WeatherProData]()
var locManager = CLLocationManager()
var currentLocation: CLLocation!
var timer = Timer()
var jour = UIColor(red: 0, green: 191 / 255, blue: 1, alpha: 1)
var nuit = UIColor(red: 51 / 255, green: 116 / 255, blue: 255 / 255, alpha: 1)
let didBecomeActiveNotificationName = UIApplication.didBecomeActiveNotification
let identifiantCell = "dataProCell"
let identifiantSegue = "versDetailDonneePro"
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var menuButton: UIBarButtonItem!
#IBOutlet weak var label: UILabel!
#IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
locManager.requestAlwaysAuthorization()
NotificationCenter.default.addObserver(self, selector: #selector(scheduleTimer), name: didBecomeActiveNotificationName, object: nil)
changeBackground()
data()
// Add Refresh Control to Table View
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.addSubview(refreshControl)
}
// Configure Refresh Control
refreshControl.addTarget(self, action: #selector(refreshWeatherData(_:)), for: .valueChanged)
refreshControl.tintColor = UIColor.white
let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
refreshControl.attributedTitle = NSAttributedString(string: "Refreshing please wait", attributes: attributes)
}
#objc private func refreshWeatherData(_ sender: Any) {
fetchWeatherData()
}
private func setupActivityIndicatorView() {
activityIndicatorView.startAnimating()
}
private func fetchWeatherData() {
data()
self.refreshControl.endRefreshing()
// self.activityIndicatorView.stopAnimating()
}
#objc func scheduleTimer() {
// schedule the timer
timer = Timer(fireAt: Calendar.current.nextDate(after: Date(), matching: DateComponents(hour: 6..<21 ~= Date().hour ? 21 : 6), matchingPolicy: .nextTime)!, interval: 0, target: self, selector: #selector(changeBackground), userInfo: nil, repeats: false)
print(timer.fireDate)
// RunLoop.main.add(timer, forMode: .RunLoop.Mode.common)
print("new background chenge scheduled at:", timer.fireDate.description(with: .current))
}
#objc func changeBackground(){
// check if day or night shift
self.view.backgroundColor = 6..<21 ~= Date().hour ? jour : nuit
// schedule the timer
scheduleTimer()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: identifiantCell) as? WeatherProCell {
let data = datas[indexPath.row]
cell.creerCell(data)
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? WeatherProCell {
cell.textIsHidden.isHidden = !cell.textIsHidden.isHidden
cell.textIsHidden1.isHidden = !cell.textIsHidden1.isHidden
cell.textIsHidden2.isHidden = !cell.textIsHidden2.isHidden
cell.textIsHidden3.isHidden = !cell.textIsHidden3.isHidden
cell.textIsHidden4.isHidden = !cell.textIsHidden4.isHidden
cell.textIsHidden5.isHidden = !cell.textIsHidden5.isHidden
cell.textIsHidden6.isHidden = !cell.textIsHidden6.isHidden
cell.textIsHidden7.isHidden = !cell.textIsHidden7.isHidden
cell.textIsHidden8.isHidden = !cell.textIsHidden8.isHidden
cell.textIsHidden9.isHidden = !cell.textIsHidden9.isHidden
cell.cloud.isHidden = !cell.cloud.isHidden
cell.rTemp.isHidden = !cell.rTemp.isHidden
cell.cloudBase.isHidden = !cell.cloudBase.isHidden
cell.dewp.isHidden = !cell.dewp.isHidden
cell.press.isHidden = !cell.press.isHidden
cell.pressIcon.isHidden = !cell.pressIcon.isHidden
cell.hydro.isHidden = !cell.hydro.isHidden
cell.hydroIcon.isHidden = !cell.hydroIcon.isHidden
cell.vent.isHidden = !cell.vent.isHidden
cell.ventIcon.isHidden = !cell.ventIcon.isHidden
cell.rainIcon.isHidden = !cell.rainIcon.isHidden
cell.rain.isHidden = !cell.rain.isHidden
cell.iso0.isHidden = !cell.iso0.isHidden
cell.freezeRain.isHidden = !cell.freezeRain.isHidden
cell.noSnow.isHidden = !cell.noSnow.isHidden
cell.snowUp.isHidden = !cell.snowUp.isHidden
cell.visibility.isHidden = !cell.visibility.isHidden
cell.snowProb.isHidden = !cell.snowProb.isHidden
tableView.beginUpdates()
tableView.endUpdates()
tableView.deselectRow(at: indexPath, animated: true)
}
}
//func numberOfSections(in tableView: UITableView) -> Int {
// return datas.count
//}
//func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
// return datas[section].date
//}
func data() {
if ( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways) {
currentLocation = locManager.location
}
var headers: HTTPHeaders = [
"Content-Type": "application/json"
]
let user = loginWeatherPro
let password = motDePasseWeatherPro
if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
headers[authorizationHeader.key] = authorizationHeader.value
}
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone.init(abbreviation: "UTC")
formatter.locale = Locale(identifier: "en_US_POSIX")
print(formatter.string(from: now))
let days = Calendar.current.date(byAdding: .day, value: 15, to: now)
let urlB = urlDeBaseWeatherPro
let locate = "locatedAt=\(currentLocation.coordinate.longitude),\(currentLocation.coordinate.latitude)"
let period = "&validPeriod=PT0S"
let validFrom = "&validFrom=\(formatter.string(from: now))"
let validUntil = "&validUntil=\(formatter.string(from: days!))"
let fields = "&fields=" + fieldsParameter
let url = urlB + locate + period + validFrom + validUntil + fields
print(url)
Alamofire.request(url, headers:headers).responseJSON{ response in
if let JSON = response.result.value as? [String: AnyObject] {
if let forecast = JSON ["forecasts"] as? NSArray {
for element in forecast {
if let dict = element as? [String: AnyObject],
let dates = dict ["validFrom"] as? String ,
let weatherCode = dict ["weatherCode"] as? Int ,
let weatherCodeString = weatherCodesTab[weatherCode],
let temp = dict ["airTemperatureInCelsius"] as? Double ,
let cloud = dict ["effectiveCloudCoverInPercent"] as? Double ,
let rtemp = dict ["feelsLikeTemperatureInCelsius"] as? Double ,
let cloudBase = dict ["cloudBaseHeightInMeter"] as? Double ,
let dewp = dict ["dewPointTemperatureInCelsius"] as? Double ,
let press = dict ["airPressureAtSeaLevelInHectoPascal"] as? Double ,
let hydro = dict ["relativeHumidityInPercent"] as? Double ,
let vent = dict ["windSpeedInKilometerPerHour"] as? Double ,
let rain = dict ["precipitationProbabilityInPercent"] as? Double ,
let iso0 = dict ["freezingLevelHeightInMeter"] as? Double ,
let freezeRain = dict ["freezingRainProbabilityInPercent"] as? Double ,
let noSnow = dict ["noSnowPossibleBelowHeightInMeter"] as? Double ,
let snowUp = dict ["snowCertainAboveHeightInMeter"] as? Double ,
let visibility = dict ["visibilityInMeter"] as? Double ,
let snowProd = dict ["snowfallProbabilityInPercent"] as? Double {
self.datas.append(WeatherProData(date: (DateHelper.obtenir.jourDeLaSemaineWeather(dates)!) + " " + DateHelper.obtenir.dateWeatherPro(dates)! + " à " + (DateHelper.obtenir.heures(dates)!), weatherCode: weatherCodeString, temp: temp, cloud: cloud, rtemp: rtemp, cloudBase: cloudBase, dewp: dewp, press: press, hydro: hydro, vent: vent, rain: rain, iso0: iso0, freezeRain: freezeRain, noSnow: noSnow, snowUp: snowUp, visibility: visibility, snowProb: snowProd))
//print(weatherCodeString)
self.tableView.reloadData()
}
}
}
}
}
}
}
The model:
import UIKit
class WeatherProData {
private var _date: String
private var _weatherCode: String
private var _temp: Double
private var _cloud: Double
private var _rTemp: Double
private var _cloudBase: Double
private var _dewp: Double
private var _press: Double
private var _hydro: Double
private var _vent: Double
private var _rain: Double
private var _iso0: Double
private var _freezeRain: Double
private var _noSnow: Double
private var _snowUp: Double
private var _visibility: Double
private var _snowProb: Double
var date: String {
return _date
}
var weatherCode: String {
return _weatherCode
}
var temp: Double {
return _temp
}
var cloud: Double {
return _cloud
}
var rtemp: Double {
return _rTemp
}
var cloudBase: Double {
return _cloudBase
}
var dewp: Double {
return _dewp
}
var press: Double {
return _press
}
var hydro: Double {
return _hydro
}
var vent: Double {
return _vent
}
var rain: Double {
return _rain
}
var iso0: Double {
return _iso0
}
var freezeRain: Double {
return _freezeRain
}
var noSnow: Double {
return _noSnow
}
var snowUp: Double {
return _snowUp
}
var visibility: Double {
return _visibility
}
var snowProb: Double {
return _snowProb
}
init(date: String, weatherCode: String, temp: Double, cloud: Double, rtemp: Double, cloudBase: Double, dewp: Double, press: Double, hydro: Double, vent: Double, rain: Double, iso0: Double, freezeRain: Double, noSnow: Double, snowUp: Double, visibility: Double, snowProb: Double) {
_date = date
_weatherCode = weatherCode
_temp = temp
_cloud = cloud
_rTemp = rtemp
_cloudBase = cloudBase
_dewp = dewp
_press = press
_hydro = hydro
_vent = vent
_rain = rain
_iso0 = iso0
_freezeRain = freezeRain
_noSnow = noSnow
_snowUp = snowUp
_visibility = visibility
_snowProb = snowProb
}
}
The cell:
import UIKit
class WeatherProCell: UITableViewCell {
#IBOutlet weak var date: UILabel!
#IBOutlet weak var temp: UILabel!
#IBOutlet weak var weatherCode: UILabel!
#IBOutlet weak var tempIcon: UIImageView!
#IBOutlet weak var textIsHidden: UILabel! {
didSet {
textIsHidden.isHidden = true
}
}
#IBOutlet weak var textIsHidden1: UILabel! {
didSet {
textIsHidden1.isHidden = true
}
}
#IBOutlet weak var textIsHidden2: UILabel! {
didSet {
textIsHidden2.isHidden = true
}
}
#IBOutlet weak var textIsHidden3: UILabel! {
didSet {
textIsHidden3.isHidden = true
}
}
#IBOutlet weak var textIsHidden4: UILabel! {
didSet {
textIsHidden4.isHidden = true
}
}
#IBOutlet weak var textIsHidden5: UILabel! {
didSet {
textIsHidden5.isHidden = true
}
}
#IBOutlet weak var textIsHidden6: UILabel! {
didSet {
textIsHidden6.isHidden = true
}
}
#IBOutlet weak var textIsHidden7: UILabel! {
didSet {
textIsHidden7.isHidden = true
}
}
#IBOutlet weak var textIsHidden8: UILabel! {
didSet {
textIsHidden8.isHidden = true
}
}
#IBOutlet weak var textIsHidden9: UILabel! {
didSet {
textIsHidden9.isHidden = true
}
}
#IBOutlet weak var cloud: UILabel! {
didSet {
cloud.isHidden = true
}
}
#IBOutlet weak var rTemp: UILabel! {
didSet {
rTemp.isHidden = true
}
}
#IBOutlet weak var cloudBase: UILabel! {
didSet {
cloudBase.isHidden = true
}
}
#IBOutlet weak var dewp: UILabel! {
didSet {
dewp.isHidden = true
}
}
#IBOutlet weak var press: UILabel! {
didSet {
press.isHidden = true
}
}
#IBOutlet weak var pressIcon: UIImageView! {
didSet {
pressIcon.isHidden = true
}
}
#IBOutlet weak var hydro: UILabel! {
didSet {
hydro.isHidden = true
}
}
#IBOutlet weak var hydroIcon: UIImageView! {
didSet {
hydroIcon.isHidden = true
}
}
#IBOutlet weak var vent: UILabel! {
didSet {
vent.isHidden = true
}
}
#IBOutlet weak var ventIcon: UIImageView! {
didSet {
ventIcon.isHidden = true
}
}
#IBOutlet weak var rainIcon: UIImageView! {
didSet {
rainIcon.isHidden = true
}
}
#IBOutlet weak var rain: UILabel! {
didSet {
rain.isHidden = true
}
}
#IBOutlet weak var iso0: UILabel! {
didSet {
iso0.isHidden = true
}
}
#IBOutlet weak var freezeRain: UILabel! {
didSet {
freezeRain.isHidden = true
}
}
#IBOutlet weak var noSnow: UILabel! {
didSet {
noSnow.isHidden = true
}
}
#IBOutlet weak var snowUp: UILabel! {
didSet {
snowUp.isHidden = true
}
}
#IBOutlet weak var visibility: UILabel! {
didSet {
visibility.isHidden = true
}
}
#IBOutlet weak var snowProb: UILabel! {
didSet {
snowProb.isHidden = true
}
}
var data: WeatherProData!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func creerCell(_ data: WeatherProData) {
self.data = data
let attributedDate = NSMutableAttributedString(string: self.data.date)
date.attributedText = attributedDate
let Cloud = "\(self.data.cloud)" + " %"
cloud.text = Cloud
let Rtemp = "\(self.data.rtemp)" + " °C"
rTemp.text = Rtemp
let CloudBase = "\(self.data.cloudBase)" + " m"
cloudBase.text = CloudBase
let Dewp = "\(self.data.dewp)" + " °C"
dewp.text = Dewp
let Temp = "\(self.data.temp)" + " °C"
temp.text = Temp
tempIcon.image = #imageLiteral(resourceName: "Termometre")
let WeatherCode = "\(self.data.weatherCode)"
weatherCode.text = WeatherCode
let Press = "\(self.data.press)" + " hpa"
press.text = Press
pressIcon.image = #imageLiteral(resourceName: "Barometre")
let Hydro = "\(self.data.hydro)" + " %"
hydro.text = Hydro
hydroIcon.image = #imageLiteral(resourceName: "Hydrometrie")
let Vent = "\(self.data.vent)" + " km/h"
vent.text = Vent
ventIcon.image = #imageLiteral(resourceName: "Vent")
let Rain = "\(self.data.rain)" + " %"
rain.text = Rain
rainIcon.image = #imageLiteral(resourceName: "Pluviometre")
let Iso0 = "\(self.data.iso0)" + " m"
iso0.text = Iso0
let FreezeRain = "\(self.data.freezeRain)" + " %"
freezeRain.text = FreezeRain
let NoSnow = "\(self.data.noSnow)" + " m"
noSnow.text = NoSnow
let SnowUp = "\(self.data.snowUp)" + " m"
snowUp.text = SnowUp
let Visibility = "\(self.data.visibility)" + " m"
visibility.text = Visibility
let SnowProb = "\(self.data.snowProb)" + " %"
snowProb.text = SnowProb
}
}
I thank you in advance for your help because I have been fighting with this for 1 month
Here is the link to my GitHub to get the complete file:
https://github.com/superdevil669/MeteoWapi_iOS_App/tree/beta
One way would be to modify your data model having an array holding the dates (the values for the sections) and a dictionary holding an array of the weather values for each date.
For the sake of simplicity I have 'simulated' this with String as data type.
// Declaration Data model
var sections = [Date]()
var datas = [Date:[String]]()
// Some test values to show how the processing could be
let date = Date()
let value = "Test"
// This would be inside your processing loop
// Check, if section already exists
if !sections.contains(date)
{
// Add date to sections array
sections.append(date)
// Insert empty array in datas dictionary
datas[date] = [String]()
}
// Add value to array
datas[date]?.append(value)
// This could be inside cellForRowAtIndexPath
// Fetch value
let indexPath = IndexPath(row: 0, section: 0)
let value2 = datas[sections[indexPath.section]]?[indexPath.row]
First of all private backing variables to get constants is horrible in Swift. You can declare constants simply with the let keyword.
If you use a struct you can even reduce WeatherProData to
struct WeatherProData {
let date: String // must be `Date` for smart grouping
let weatherCode: String
let temp: Double
let cloud: Double
let rTemp: Double
let cloudBase: Double
let dewp: Double
let press: Double
let hydro: Double
let vent: Double
let rain: Double
let iso0: Double
let freezeRain: Double
let noSnow: Double
let snowUp: Double
let visibility: Double
let snowProb: Double
}
because you get the init method for free
Grouping an array is very easy in Swift. The suggestion below assumes that date is declared and decoded as Date.
Dictionary(grouping:by: groups the array by the condition in the closure in this case midnight of the current date.
let calendar = Calendar.current
let grouped = Dictionary(grouping: datas, by: { calendar.startOfDay(for: $0.date) })
print(grouped)
And in Swift 4.2+ you can negate a boolean with
cell.textIsHidden.isHidden.toggle()
Consider also to use the Deodable protocol to get rid of the manual decoding.
I tried another project so as not to damage mine.
import UIKit
import Alamofire
struct WeatherProData {
let date: String // must be `Date` for smart grouping
// let weatherCode: String
// let temp: Double
// let cloud: Doublea
// let rTemp: Double
// let cloudBase: Double
// let dewp: Double
// let press: Double
// let hydro: Double
// let vent: Double
// let rain: Double
// let iso0: Double
// let freezeRain: Double
// let noSnow: Double
// let snowUp: Double
// let visibility: Double
// let snowProb: Double
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var data = [WeatherProData]()
var sections = [Date]()
var dataT = [Date:[String]]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
let date = Date()
let value = "Test"
if !sections.contains(date) {
sections.append(date)
dataT[date] = [String]()
}
dataT[date]?.append(value)
var headers : HTTPHeaders = ["Content-Type":"application.json"]
// Ajout lofin et mot de passe pour la connection à weather pro
let user = loginWeatherPro
let password = motDePasseWeatherPro
// Ajout de l'autorisation de connection
if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
headers[authorizationHeader.key] = authorizationHeader.value
}
// formattage de l'heure
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone.init(abbreviation: "UTC")
formatter.locale = Locale(identifier: "en_US_POSIX")
print(formatter.string(from: now))
let days = Calendar.current.date(byAdding: .day, value: 1, to: now)
// preparation de l'url de base
let urlB = urlDeBaseWeatherPro
let locate = "locatedAt=3.284752,50.644164"
let period = "&validPeriod=PT0S"
let validFrom = "&validFrom=\(formatter.string(from: now))"
let validUntil = "&validUntil=\(formatter.string(from: days!))"
let fields = "&fields=" + fieldsParameter
let url = urlB + locate + period + validFrom + validUntil + fields
Alamofire.request(url, headers:headers).responseJSON { response in
if let JSON = response.result.value as? [String: AnyObject] {
if let forecast = JSON ["forecasts"] as? NSArray {
for element in forecast {
if let dict = element as? [String: AnyObject],
let dates = dict ["validFrom"] as? String {
self.data.append(WeatherProData(date: dates))
print(dates)
self.tableView.reloadData()
}
}
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return dataT.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "test"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let datas = data[indexPath.row]
cell.textLabel?.text = datas.date
return cell
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.reloadData()
}
}
I did the simplest thing, but I can't classify my UITableView not section I think it must be due to the JSON file that sends me this as date.
2019-01-14T10:34:04Z
2019-01-14T12:00:00+01:00
2019-01-14T13:00:00+01:00
2019-01-14T14:00:00+01:00
2019-01-14T15:00:00+01:00
2019-01-14T16:00:00+01:00
2019-01-14T17:00:00+01:00
2019-01-14T18:00:00+01:00
2019-01-14T19:00:00+01:00
2019-01-14T20:00:00+01:00
2019-01-14T21:00:00+01:00
2019-01-14T22:00:00+01:00
2019-01-14T23:00:00+01:00
2019-01-15T00:00:00+01:00
2019-01-15T01:00:00+01:00
2019-01-15T02:00:00+01:00
2019-01-15T03:00:00+01:00
2019-01-15T04:00:00+01:00
2019-01-15T05:00:00+01:00
2019-01-15T06:00:00+01:00
2019-01-15T07:00:00+01:00
2019-01-15T08:00:00+01:00
2019-01-15T09:00:00+01:00
2019-01-15T10:00:00+01:00
2019-01-15T11:00:00+01:00
Thank you. Thank you.
I'm still trying. I can create my sections but I can't display them without the hours.
I would like each section to have the title of the day, and below that the hours of each day.
import UIKit
import Alamofire
struct WeatherProData {
let date: String // must be `Date` for smart grouping
// let weatherCode: String
// let temp: Double
// let cloud: Doublea
// let rTemp: Double
// let cloudBase: Double
// let dewp: Double
// let press: Double
// let hydro: Double
// let vent: Double
// let rain: Double
// let iso0: Double
// let freezeRain: Double
// let noSnow: Double
// let snowUp: Double
// let visibility: Double
// let snowProb: Double
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#objc func refresh(_ sender: Any) {
// Call webservice here after reload tableview.
tableView.reloadData()
refreshControl.endRefreshing()
}
var data = [WeatherProData]()
var sections = [String]()
var dateSection = [[WeatherProData]]()
var refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// RefrechControl sur UITableVIew
refreshControl.attributedTitle = NSAttributedString(string: "Tirez pour rafraichir")
refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
self.tableView.addSubview(refreshControl)
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
var headers : HTTPHeaders = ["Content-Type":"application.json"]
// Ajout lofin et mot de passe pour la connection à weather pro
let user = loginWeatherPro
let password = motDePasseWeatherPro
// Ajout de l'autorisation de connection
if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
headers[authorizationHeader.key] = authorizationHeader.value
}
// formattage de l'heure
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone.init(abbreviation: "UTC")
formatter.locale = Locale(identifier: "en_US_POSIX")
print(formatter.string(from: now))
let days = Calendar.current.date(byAdding: .day, value: 1, to: now)
let french = DateFormatter()
french.dateStyle = .full
french.dateFormat = "dd MMMM"
french.locale = Locale(identifier: "FR_fr")
print(french.string(from: now))
// preparation de l'url de base
let urlB = urlDeBaseWeatherPro
let locate = "locatedAt=3.284752,50.644164"
let period = "&validPeriod=PT0S"
let validFrom = "&validFrom=\(formatter.string(from: now))"
let validUntil = "&validUntil=\(formatter.string(from: days!))"
let fields = "&fields=" + fieldsParameter
let url = urlB + locate + period + validFrom + validUntil + fields
Alamofire.request(url, headers:headers).responseJSON { response in
if let JSON = response.result.value as? [String: Any] {
if let forecast = JSON ["forecasts"] as? NSArray {
for element in forecast {
if let dict = element as? [String: Any],
let dates = dict ["validFrom"] as? String {
self.data.append(WeatherProData(date: dates))
self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
WeatherProData.date
})))
self.sections.forEach({ (string) in self.dateSection.append([])})
for index in 0..<self.sections.count {
self.data.forEach({ (data) in
if data.date == self.sections[index] {
self.dateSection[index].append(data)
}
})
}
self.tableView.reloadData()
}
}
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
for index in 0..<sections.count {
if index == section {
return dateSection[index].count
}
}
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// let datas = data[indexPath.row]
cell.textLabel?.text = dateSection[indexPath.section] [indexPath.row].date
// cell.textLabel?.text = datas.date
self.tableView.addSubview(self.refreshControl)
return cell
}
}
This is what I get.
My UITableView
In
self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
WeatherProData.date
})))
, when you have -> String means that the function is asking you to return a string value. So you need to add a return with the string value in your code.
Here is a working code for your situation :
self.sections = Array(Set(self.data.map({ (WeatherProData) -> String in
let jsonDateString = WeatherProData.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXX"
if let weatherProDataDate = dateFormatter.date(from: jsonDateString) {
return french.string(from: weatherProDataDate)
} else {
return ""
}
})))
I am currently using a table view to display a menu, in which people can click on the add or subtract buttons to increase/decrease their order.
This table view has approximately 30 items and so you have to scroll down to get to all the menu items. The problem is, when you scroll down, the table view cells above the scroll (that are now hidden) lose the data that they have just contained.
For example, if you have a menu item that you have ordered 2 of an item, that 2 on the label has now turned back to 0. This is very object oriented so I am not sure why this is happening.
My table view class:
#IBOutlet weak var appetizerTableView: UITableView!
var appetizerList = [OrderModel]()
let ref = FIRDatabase.database().reference()
override func viewDidLoad() {
appetizerTableView.delegate = self
appetizerTableView.dataSource = self
ref.child("Broadway").child("AppetizerDishes").observeSingleEventOfType(.Value, withBlock: { snapshot in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print("WILL: \(snap)")
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let post = OrderModel(postkey: key, postData: postDict)
self.appetizerList.append(post)
}
}
}
self.appetizerTableView.reloadData()
})
}
var data=[OrderModel]()
func addButtonAction(addedList:[String:Float]) {
print("WILLCOHEN:\(addedList)")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return appetizerList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
if let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell{
cell.configureCell(post)
cell.delegate = self
return cell
} else {
return OrderCell()
}
}
}
My cell model class:
class OrderModel {
private var _dishName: String!
private var _dishDescription: String!
private var _numberOfOrders: Int!
private var _postKey: String!
private var _dishPrice: Float!
var dishName: String {
return _dishName
}
var dishDescription: String {
return _dishDescription
}
var numberOfOrders: Int {
get {
return _numberOfOrders
}
set (newVal) {
_numberOfOrders = newVal
}
}
var postKey: String {
return _postKey
}
var dishPrice: Float {
return _dishPrice
}
init(dishName: String, dishDescription: String, numberOfOrders: Int) {
self._dishName = dishName
self._dishDescription = dishDescription
}
init(postkey: String, postData: Dictionary<String, AnyObject>) {
self._postKey = postkey
if let dishName = postData["dishName"] as? String {
self._dishName = dishName
}
if let dishDescription = postData["dishDescription"] as? String {
self._dishDescription = dishDescription
}
if let numberOfOrders = postData["anumberOfOrders"] as? Int {
self._numberOfOrders = numberOfOrders
}
if let dishPrice = postData["dishPrice"] as? Float32 {
self._dishPrice = dishPrice
}
}
}
My cell class:
protocol ClassNameDelegate:class {
func addButtonAction(addedList:[String:Float])
}
var addedList: [String:Float] = [:]
class OrderCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
var post: OrderModel!
var link: Link!
#IBOutlet weak var dishName: UILabel!
#IBOutlet weak var dishDescriptionAndPrice: UILabel!
#IBOutlet weak var numberOfOrders: UILabel!
#IBOutlet weak var addOrderBtn: UIButton!
#IBOutlet weak var subtractOderBtn: UIButton!
weak var delegate: ClassNameDelegate?
#IBAction func addButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 9 {
numberOfOrders.text = "9"
} else {
if addedList[post.dishName] != nil {
addedList[post.dishName] = post.dishPrice
} else {
addedList["\(post.dishName) \(Int(numberOfOrders.text!)! + 1)"] = post.dishPrice
}
post.numberOfOrders = post.numberOfOrders - 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
if delegate != nil {
delegate?.addButtonAction(addedList)
}
}
#IBAction func subtractButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 0 {
numberOfOrders.text = "0"
} else {
post.numberOfOrders = post.numberOfOrders + 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
}
func getOrders() -> Dictionary<String, Float> {
return addedList
}
func configureCell(post: OrderModel) {
self.post = post
self.dishName.text = post.dishName
self.dishDescriptionAndPrice.text = post.dishDescription
self.numberOfOrders.text = "0"
}
}
I should mention that I am pulling my table view data from Firebase.
Thank you in advance for any help or suggestions, it is very much appreciated.
You are calling configureCell(post:) on every cell, and in the configureCell(post:) function you set the text value of the numbersOfOrders label to "0". You should probably set the text to a value in the OrderModel/post argument.
Also, you should be sure to always call configureCell(post:) (you are not calling it if you have to manually create an OrderCell), so your tableView(tableView:cellForRowAtIndexPath:) function should look like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell ?? OrderCell()
cell.configureCell(post)
cell.delegate = self
return cell
}
I have one screen like the following picture:
I uploaded list with student name by using custom cell as you are seeing and I want when click on save button save the status of student in array , I initialized array with 0 for all student at the first time and when the status of switch is enabled then this value at the clicked cell index converted to 1 but I couldn't make that when the click action happened on switch this is only now happening when click on the cell ( row ) how I can do the same thing when only change the status of switch to update the array without click on complete row at table
Code of main view :
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.studentNameLabel.text = student_name[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
student_attendance[indexPath.row] = currentCell.status
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance) // this only to ensure from the final array before sending to server
}
func loadList()
{
var normallink = "myurl"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
}
Cell Code :
class teacherAttendanceCell: UITableViewCell {
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
Updated:
Main View Controller:
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate,CellInfoDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.delegate = self
cell.studentNameLabel.text = student_name[indexPath.row]
student_attendance[indexPath.row] = cell.status
//print(student_attendance.count)
//let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance.append(cell.status)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
// let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance[indexPath.row] = currentCell.status
//print("OK Status here!" + String(student_attendance.count))
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance)
}
func loadList()
{
var normallink = "mylinkhere"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
func processThatNumber(theStatus: String) {
print("out : \(theStatus)")
}
}
protocol CellInfoDelegate {
func processThatNumber(theStatus: String)
}
Cell View Controller:
import UIKit
class teacherAttendanceCell: UITableViewCell{
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
var delegate: CellInfoDelegate?
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
if let delegate = self.delegate {
delegate.processThatNumber(self.status)
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
There are few ways to do this: using closure or delegate, but I preferred to use delegate.
Create a delegate for your teacherAttendanceCell cell like in this answer https://stackoverflow.com/a/25792213/2739795
Make you teacherAttendanceVC conforms the delegate
Each time when cellForRowAtIndexPath calls set cell.delegate = self. Also return the cell into your delegate method
Call method from delegate insidestateChanged
And when delegate method calls you can get an index if switched cell
tableView.indexPathForCell(cellFromParam)
var duration = waveFnList.waves[indexPath.row].duration
if let _duration = String(duration) {
viewDuration = _duration
} else {
viewDuration = ""
}
I'm trying to convert duration (of type Int) to a String using String(duration). I am getting an error:
Could not find an overload for 'init' that accepts the supplied arguments
EDIT: I will post more of the code for a better understanding:
GLOBAL:
import Foundation
var waveFnList: WaveFunctionList = WaveFunctionList()
var viewName:String = ""
var viewDuration:String = ""
var viewPeriod:String = ""
var viewMinAmp:String = ""
var viewMaxAmp:String = ""
var viewStep:String = ""
var viewType:String = ""
var waveTypes: [Int: String] = [
0: "Sine",
1: "Saw",
2: "Square",
3: "Triangle",
4: "Flat"
]
struct WaveFunction {
var name: String?
var duration: Int?
var period: Int?
var minAmp: Int?
var maxAmp: Int?
var step: Int?
var type: Int?
}
class WaveFunctionList: NSObject {
var waves = [WaveFunction]()
func addWave(name: String, duration: Int, period: Int, minAmp: Int, maxAmp: Int, step: Int, type: Int) {
waves.append(WaveFunction(name: name, duration: duration, period: period, minAmp: minAmp, maxAmp: maxAmp, step: step, type: type))
}
}
FIRST VIEW CONTROLLER
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tblWaveFunctions: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Returning to view
override func viewWillAppear(animated: Bool) {
tblWaveFunctions.reloadData()
}
//UITableViewDelete
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
waveFnList.waves.removeAtIndex(indexPath.row)
tblWaveFunctions.reloadData()
}
}
//UITableViewDataSource
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return waveFnList.waves.count
}
//Cell data
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell: UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Subtitle, reuseIdentifier: "test")
cell.textLabel.text = waveFnList.waves[indexPath.row].name
cell.detailTextLabel.text = waveTypes[waveFnList.waves[indexPath.row].type!]
return cell
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
// Get the row data for the selected row
/*
var alert: UIAlertView = UIAlertView()
alert.title = waveFnList.waves[indexPath.row].name
alert.message = waveTypes[waveFnList.waves[indexPath.row].type!]
alert.addButtonWithTitle("Ok")
alert.show()
*/
if let _name = waveFnList.waves[indexPath.row].name {
viewName = _name
} else {
viewName = ""
}
var duration = waveFnList.waves[indexPath.row].duration
if let _duration = String(duration) {
viewDuration = _duration
} else {
viewDuration = ""
}
var period = waveFnList.waves[indexPath.row].period
if let _period = String(period) {
viewPeriod = _period
} else {
viewPeriod = ""
}
var min_Amp = waveFnList.waves[indexPath.row].minAmp
if let _min_Amp = String(min_Amp) {
viewMinAmp = _min_Amp
} else {
viewMinAmp = ""
}
var max_Amp = waveFnList.waves[indexPath.row].maxAmp
if let _max_Amp = String(max_Amp) {
viewMaxAmp = _max_Amp
} else {
viewMaxAmp = ""
}
var step = waveFnList.waves[indexPath.row].step
if let _step = String(step) {
viewStep = _step
} else {
viewStep = ""
}
var type = waveFnList.waves[indexPath.row].step
if let _type = String(type) {
viewType = _type
} else {
viewType = ""
}
self.tabBarController.selectedIndex = 1 //go back to firstView
}
}
SECOND VIEW CONTROLLER
import UIKit
class SecondViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var txtName: UITextField!
#IBOutlet var txtDuration: UITextField!
#IBOutlet var txtPeriod: UITextField!
#IBOutlet var txtMinAmp: UITextField!
#IBOutlet var txtMaxAmp: UITextField!
#IBOutlet var txtStep: UITextField!
#IBOutlet var txtType: UITextField!
override func loadView() {
println("despues")
println(viewName)
setInfo(viewName, duration: viewDuration, period: viewPeriod, minAmp: viewMinAmp, maxAmp: viewMaxAmp, step: viewStep, type: viewType)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Events
#IBAction func btnAddWaveFunction_Click(sender: UIButton) {
waveFnList.addWave(txtName.text, duration: txtDuration.text.toInt()!, period: txtPeriod.text.toInt()!, minAmp: txtMinAmp.text.toInt()!, maxAmp: txtMaxAmp.text.toInt()!, step: txtStep.text.toInt()!, type: txtType.text.toInt()!)
self.view.endEditing(true) //hide keyboard
txtName.text = ""
txtDuration.text = ""
txtPeriod.text = ""
txtMinAmp.text = ""
txtMaxAmp.text = ""
txtStep.text = ""
txtType.text = ""
self.tabBarController.selectedIndex = 0 //go back to firstView
}
//iOS Touch Functions
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
self.view.endEditing(true)
}
//UITextField Delegate
//Hide keyboard when click return
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder()
return true
}
func setInfo(name: String?, duration: String, period: String, minAmp: String, maxAmp: String, step: String, type: String) {
txtName.text = name
txtDuration.text = duration
txtPeriod.text = period
txtMinAmp.text = minAmp
txtMaxAmp.text = maxAmp
txtStep.text = step
txtType.text = type
}
}
String cannot init with Int?, but it can with Int. Since String(int:Int) doesn't return an optional, you can get the effect you want with the same amount of code:
if let _duration = duration {
viewDuration = String(_duration)
} else {
viewDuration = ""
}
Also, try below code :
if let _duration = duration {
viewDuration = _duration.integerValue
} else {
viewDuration = ""
}
I hope, these works for you . . .