Parsing json data through alamofire in table view cells - ios

I am trying to parse json data in my table view cell and its not parsing and not showing the cells . I am attaching all my code please tell me whats the mistake i am doing .. I am not getting any error but the cells are not showing. I have made separate class and functions for json parsing and storing it in an array .
//
// ViewController.swift
// WorkingFeed2
//
// Created by keshu rai on 08/08/17.
// Copyright © 2017 keshu rai. All rights reserved.
//
import UIKit
import Alamofire
import MediaPlayer
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource{
var post : PostData!
var posts = [PostData]()
typealias DownloadComplete = () -> ()
var arrayOfPostData : [String] = []
#IBOutlet weak var feedTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
feedTable.dataSource = self
feedTable.delegate = self
}
func downloadPostData(completed: #escaping DownloadComplete) {
Alamofire.request("https://new.example.com/api/posts/get_all_posts").responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String,AnyObject> {
if let successcode = dict["STATUS_CODE"] as? Int {
if successcode == 1 {
if let postsArray = dict["posts"] as? [Dictionary<String,AnyObject>]
{
for obj in postsArray
{
let post = PostData(postDict: obj)
self.posts.append(post)
print(obj)
}
// self.posts.remove(at: 0)
self.feedTable.reloadData()
}
}
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 419
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : ImageTableViewCell = self.feedTable.dequeueReusableCell(withIdentifier: "contentViewReuse") as! ImageTableViewCell
let post = posts[indexPath.row]
print(post)
cell.configureCell(post : post)
return cell
}
}
This is my PostData Class.
import Foundation
class PostData {
var _profileImageURL : String?
var _fullName : String?
var _location : String?
var _title : String?
var _postTime : String?
var _likes : Int?
var _comments : Int?
var _mediaType : String?
var _contentURL : String?
var _content : String?
var _plocation : String?
var profileImageURL : String
{
if _profileImageURL == nil {
_profileImageURL = ""
}
return _profileImageURL!
}
var fullName : String
{
if _fullName == nil {
_fullName = ""
}
return _fullName!
}
var location : String {
if _location == nil {
_location = ""
}
return _location!
}
var title : String {
if _title == nil {
_title = ""
}
return _title!
}
var postTime : String {
if _postTime == nil {
_postTime = ""
}
return _postTime!
}
var likes : Int {
if _likes == nil {
_likes = 0
}
return _likes!
}
var comments : Int {
if _comments == nil {
_comments = 0
}
return _comments!
}
var mediaType : String {
if _mediaType == nil {
_mediaType = ""
}
return _mediaType!
}
var contentURL : String {
if _contentURL == nil {
_contentURL = ""
}
return _contentURL!
}
var content : String {
if _content == nil {
_content = ""
}
return _content!
}
var pLocation : String {
if _plocation == nil {
_plocation = ""
}
return _plocation!
}
init(postDict : Dictionary<String , AnyObject>)
{
if let postsArray = postDict["posts"] as? [Dictionary<String,AnyObject>]
{
for i in 1..<postsArray.count
{
let fullName1 = postsArray[i]["full_name"] as? String
self._fullName = fullName1
let profileImageURL1 = postsArray[i]["profile_pic"] as? String
self._profileImageURL = profileImageURL1
let location1 = postsArray[i]["user_city"] as? String
self._location = location1
let title1 = postsArray[i]["title"] as? String
self._title = title1
let postTime1 = postsArray[i]["order_by_date"] as? String
self._postTime = postTime1
let likes1 = postsArray[i]["liked_count"] as? Int
self._likes = likes1
let comments1 = postsArray[i]["comment_count"] as? Int
self._comments = comments1
let mediaType1 = postsArray[i]["media_path"] as? String
self._mediaType = mediaType1
let contentURL1 = postsArray[i]["media_path"] as? String
self._contentURL = contentURL1
let content1 = postsArray[i]["content"] as? String
self._content = content1
let plocation1 = postsArray[i]["location"] as? String
self._plocation = plocation1
}
}
}
}
This is my PostDataTableViewCell code.
import UIKit
import Alamofire
class PostDataTableViewCell: UITableViewCell {
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var titlePost: UILabel!
#IBOutlet weak var profileFullName: UILabel!
#IBOutlet weak var profileUserLocation: UILabel!
#IBOutlet weak var likeBtn: UIButton!
var buttonAction: ( () -> Void) = {}
var pressed = false
#IBAction func likeBtnPressed(_ sender: Any) {
if !pressed {
let image = UIImage(named: "Like-1.png") as UIImage!
likeBtn.setImage(image, for: .normal)
pressed = true
} else {
let image = UIImage(named: "liked.png") as UIImage!
likeBtn.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
UIView.animate(withDuration: 2.0,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 6.0,
options: .allowUserInteraction,
animations: { [weak self] in
self?.likeBtn.transform = .identity
},
completion: nil)
likeBtn.setImage(image, for: .normal)
pressed = false
}
}
#IBAction func commentBtnPressed(_ sender: Any) {
print("Commented")
}
#IBAction func shareBtnPressed(_ sender: Any) {
self.buttonAction()
}
#IBAction func readContentBtnPressed(_ sender: Any) {
print("Read")
}
#IBOutlet weak var contentPostLabel: UILabel!
#IBOutlet weak var contentTypeView: UIView!
#IBOutlet weak var likeAndCommentView: UIView!
#IBOutlet weak var numberOfLikes: UILabel!
#IBOutlet weak var numberOfComments: UILabel!
#IBOutlet weak var postLocation: UILabel!
#IBOutlet weak var postTimeOutlet: UILabel!
func configureCell(post : PostData)
{
titlePost.text = "\(post.title)"
profileFullName.text = "\(post.fullName)"
profileUserLocation.text = "\(post.location)"
numberOfLikes.text = "\(post.likes) Likes"
numberOfComments.text = "\(post.comments) Comments"
postLocation.text = "\(post.pLocation)"
postTimeOutlet.text = "\(post.postTime)"
let url = URL(string: post.profileImageURL)
let data = try? Data(contentsOf: url!)
profileImage.image = UIImage(data: data!)
contentPostLabel.text = "\(post.content)"
if post.mediaType == "image"
{
let url1 = URL(string: post.contentURL)
let data1 = try? Data(contentsOf: url1!)
let image = UIImage(data: data1!)
let imageToView = UIImageView(image: image!)
imageToView.frame = CGRect(x: 0, y: 0, width: 375 , height: 250)
imageToView.contentMode = UIViewContentMode.scaleToFill
contentTypeView.addSubview(imageToView)
}
else if post.mediaType == "null"
{
print("Status")
}
else if post.mediaType == "video"
{
print("Video")
}
else if post.mediaType == "youtube"
{
print("youtube")
}
}
}

Most likely the issue occurs because you are trying to parse the value for key posts twice, once in PostData and once in ViewController.
First of all in Swift 3 a JSON dictionary is [String:Any], secondly – as already mentioned in my comment – private backing variables are nonsense in Swift.
The class PostData can be reduced to
class PostData {
let profileImageURL : String
let fullName : String
let location : String
let title : String
let postTime : String
let likes : Int
let comments : Int
let mediaType : String
let contentURL : String
let content : String
let plocation : String
init(postDict : [String:Any])
{
fullName = postDict["full_name"] as? String ?? ""
profileImageURL = postDict["profile_pic"] as? String ?? ""
location = postDict["user_city"] as? String ?? ""
title = postDict["title"] as? String ?? ""
postTime = postDict["order_by_date"] as? String ?? ""
likes = postDict["liked_count"] as? Int ?? 0
comments = postDict["comment_count"] as? Int ?? 0
mediaType = postDict["media_path"] as? String ?? ""
contentURL = postDict["media_path"] as? String ?? ""
content = postDict["content"] as? String ?? ""
plocation = postDict["location"] as? String ?? ""
}
}

Related

Adding a local variable to downloaded MySQL Data with Models

I am using MySQL and PHP to download a restaurants menu but the user of the app should be able to add a certain amount to which item from the menu they want. Currently I am using a stepper to indicate the amount and adding that amount to a UserDefaults key which gets called when the menu is downloaded again.
This makes me have to download the menu again when I go to another viewController which sums up the order but I can't seem to filter out only them items which do have an amount.
What is a better way to add that amount to the downloaded data and how can I filter these items in my cart ViewController to only show and use the items which have an amount.
My current downloadModel, MenuModel, cellViewController (for the menu tableview) look like this:
MenuDownload.swift:
import UIKit
protocol MenuDownloadProtocol: class {
func productsDownloaded(products: NSArray)
}
class MenuDownload: NSObject {
//properties
weak var delegate: MenuDownloadProtocol!
func downloadProducts() {
let urlPath = "http://server.com/download.php" // Fake URL obviously
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Menu downloaded")
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()
let products = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let restomenu = MenuModel()
//the following insures none of the JsonElement values are nil through optional binding
if let product = jsonElement["product"] as? String,
let price = jsonElement["price"] as? String,
let info = jsonElement["info"] as? String,
let imageurl = jsonElement["imageurl"] as? String
{
let productandprice = product + " " + "€" + price
let quantityy = UserDefaults.standard.object(forKey: productandprice) as? String
restomenu.product = product
restomenu.price = price
restomenu.info = info
restomenu.imageurl = imageurl
restomenu.quantity = quantityy
}
products.add(restomenu)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.productsDownloaded(products: products)
})
}
}
extension String {
func chopPrefix(_ count: Int = 1) -> String {
return substring(from: index(startIndex, offsetBy: count))
}
func chopSuffix(_ count: Int = 1) -> String {
return substring(to: index(endIndex, offsetBy: -count))
}
}
MenuModel.swift:
import UIKit
class MenuModel: NSObject {
//properties
var product: String?
var price: String?
var info: String?
var imageurl: String?
var quantity: String?
//empty constructor
override init()
{
}
init(product: String, price: String, info: String, imageurl: String, quantity: String) {
self.product = product
self.price = price
self.info = info
self.imageurl = imageurl
self.quantity = quantity
}
//prints object's current state
override var description: String {
return "product: \(String(describing: product)), price: \(String(describing: price)), info: \(String(describing: info)), imageurl: \(String(describing: imageurl)), quantity: \(String(describing: quantity))"
}
}
tableViewCell.swift:
import UIKit
class productTableViewCell: UITableViewCell {
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var cellView: UIView!
#IBOutlet weak var orderCount: UILabel!
#IBOutlet weak var stepper: UIStepper!
var amount: String?
#IBAction func stepperValueChanged(_ sender: UIStepper) {
amount = Int(sender.value).description
orderCount.text = amount
// let defaultkey = String(productLabel.text!)
UserDefaults.standard.setValue(amount, forKey: productLabel.text!)
if amount == "0"
{
orderCount.isHidden = true
UserDefaults.standard.removeObject(forKey: productLabel.text!)
}
else
{
orderCount.isHidden = false
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
EDIT: after trying filtering options and many different ways I still haven't found how to fix this. I think I'm overthinking it too much.

How can i get global defined like "dictionary.count" return value?

I'm trying to fetch specific user messages from Firebase Real-Time database.I want to fill chatLogTableView with the user messages.I'm fetching user messages datas from firebase with fetchCurrentUserMessages() function.
In this function :
self.messagesDatas.append(message)
print(self.messagesDatas)
When i try to print the self.messagesDatas its okay.But when the tableview trying to retrieve self.messagesDatas.count for numberOfRowsInSection i'm getting 0 count.Why this is happening ?
Here is my code :
import UIKit
import Firebase
class ChatLogCustomCell: UITableViewCell {
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
}
class ChatLogViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var chatLogTableView: UITableView!
#IBOutlet weak var messageTextField: UITextField! // bu kismi elle yazman gerekebilir cunku xcode bu messagetextfield i sanki view in icinde oldugu icin table view icinde algilayamayabilir
#IBOutlet weak var backButton: UINavigationItem!
var usersDataFromChatScreen = [User]()
var selectedUserToIDFromChatScreen = ""
var isTeacherFromChatScreen = ""
var messagesDatas = [Message]()
var messagesDictionary = [String : Message]()
override func viewDidLoad() {
super.viewDidLoad()
chatLogTableView.delegate = self
chatLogTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messagesDatas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = chatLogTableView.dequeueReusableCell(withIdentifier: "chatLogCell") as! ChatLogCustomCell
let message = messagesDatas[indexPath.row]
cell.leftLabel.text = message.text
cell.rightLabel.text = message.text
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
#IBAction func sendButtonTouchOnInside(_ sender: Any) {
let ref = Database.database().reference().child("messages")
let childRef = ref.childByAutoId()
let toID = selectedUserToIDFromChatScreen
Auth.auth().addStateDidChangeListener { (auth, user) in
let fromID = auth.currentUser?.uid
let values = ["text" : self.messageTextField.text, "toID" : toID, "fromID" : fromID] as [String : Any]
childRef.updateChildValues(values) { (error, ref) in
if error != nil {
print(error ?? "")
return
}
guard let messageID = childRef.key else { return }
let userMessagesRef = Database.database().reference().child("user-messages").child(fromID!).child(messageID)
userMessagesRef.setValue(1)
let recipientUserMessagesRef = Database.database().reference().child("user-messages").child(toID).child(messageID)
recipientUserMessagesRef.setValue(1)
}
}
}
func fetchCurrentUserMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
if self.isTeacherFromChatScreen == "no" {
let ref = Database.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded) { (snapshot) in
let messageID = snapshot.key
let messagesRef = Database.database().reference().child("messages").child(messageID)
messagesRef.observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else {
return
}
let message = Message()
let toID = dictionary["toID"] as? String ?? "toID not found"
let messageText = dictionary["text"] as? String ?? "Text not found"
let fromID = dictionary["fromID"] as? String ?? "fromID not found"
message.toID = toID
message.text = messageText
message.fromID = fromID
self.messagesDatas.append(message)
print(self.messagesDatas.count)
}
}
}
else {
}
}
}
Reload your tableview when you get data from server
func fetchCurrentUserMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
if self.isTeacherFromChatScreen == "no" {
let ref = Database.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded) { (snapshot) in
let messageID = snapshot.key
let messagesRef = Database.database().reference().child("messages").child(messageID)
messagesRef.observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else {
return
}
let message = Message()
let toID = dictionary["toID"] as? String ?? "toID not found"
let messageText = dictionary["text"] as? String ?? "Text not found"
let fromID = dictionary["fromID"] as? String ?? "fromID not found"
message.toID = toID
message.text = messageText
message.fromID = fromID
self.messagesDatas.append(message)
print(self.messagesDatas.count)
DispatchQueue.main.async {
chatLogTableView.reloadData()
}
}
}
}
else {
}
}

Add sections from a JSON file to a TableView

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 ""
}
})))

Swift - Grab data from Firebase and store it into an array

I am trying to grab a list of bars from a Firebase Database and store it in an array so I can display it in a table view.
I have configured Firebase and managed to get data in the app as String, AnyObject dictionary.
Here is my code :
struct Bar {
var latitude: Double?
var longitude: Double?
var name: String!
var phoneNumber: String?
var happyHour: String?
var url: NSURL?
var barLogo: UIImage?
var followers: Int?
var addedToFavorites: Int?
var zipCode: Double?
var area: String?
}
class ViewController: UIViewController {
var ref: FIRDatabaseReference!
var refHandle: UInt!
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
refHandle = ref.observe(FIRDataEventType.value , with: {(snapshot) in
let dataDict = snapshot.value as! [String : AnyObject]
}
)
}
Here is my JSON exported from Firebase:
{
"data" : {
"bars" : {
"bar1" : {
"addedToFavorites" : 0,
"area" : "upper east",
"follwers" : 0,
"happyHour" : "m-f 16-19",
"lattitude" : 4412334,
"longitude" : 223455,
"name" : "bar1",
"phone" : 212222,
"url" : "http://www.bar1.com",
"zipCode" : 12345
},
"bar2" : {
"addedToFavorites" : 0,
"area" : "upper west",
"follwers" : 0,
"happyHour" : "f - s 20-22",
"lattitude" : 4443221,
"longitude" : 221234,
"name" : "bar 2",
"phone" : 215555,
"url" : "http://www.bar2.com",
"zipCode" : 54321
}
}
}
}
What would be the best approach for this?
I would like to scale it and download hundreds of bars, so manually grabbing the data from the dictionary and storing it into a Bar struct variable and then appending it to an array is not a path I want to go on.
I need a solution to grab all the bars and somehow adding them to an array (or any other method to display them into a tableView).
Thanks in advance.
I found a way to solve this issue :
First of all I got rid of the struct and created a class :
My class file :
import Foundation
import UIKit
class Bar {
private var _name: String!
private var _area: String!
private var _latitude: Double!
private var _longitude: Double!
private var _followers: Int!
private var _happyHour: String!
private var _phone: Double!
private var _url: String!
private var _zipCode: Double!
private var _addedToFav: Int!
var name: String! {
return _name
}
var area: String! {
return _area
}
var latitude: Double! {
return _latitude
}
var longitude: Double! {
return _longitude
}
var followers: Int! {
return _followers
}
var happyHour: String! {
return _happyHour
}
var phone: Double! {
return _phone
}
var url: String! {
return _url
}
var zipCode: Double! {
return _zipCode
}
var addedToFav: Int! {
return _addedToFav
}
init(name: String,area: String! , latitude: Double, longitude: Double, followers: Int, happyHour: String, phone: Double, url: String, zipCode: Double, addedToFav: Int) {
self._name = name
self._area = area
self._latitude = latitude
self._longitude = longitude
self._followers = followers
self._happyHour = happyHour
self._phone = phone
self._url = url
self._zipCode = zipCode
self._addedToFav = addedToFav
}
init(barData: Dictionary<String, AnyObject>) {
if let name = barData["name"] as? String {
self._name = name
}
if let area = barData["area"] as? String {
self._area = area
}
if let latitude = barData["lattitude"] as? Double {
self._latitude = latitude
}
if let longitude = barData["longitude"] as? Double {
self._longitude = longitude
}
if let followers = barData["followers"] as? Int {
self._followers = followers
}
if let happyHour = barData["happyHour"] as? String {
self._happyHour = happyHour
}
if let phone = barData["phone"] as? Double {
self._phone = phone
}
if let url = barData["url"] as? String {
self._url = url
}
if let zipCode = barData["zipCode"] as? Double {
self._zipCode = zipCode
}
if let addedToFav = barData["addedToFavorites"] as? Int {
self._addedToFav = addedToFav
}
}
}
I created a DataService class with a singleton
Data service class file:
import Foundation
import Firebase
let URL_BASE = FIRDatabase.database().reference()
class DataService {
static let ds = DataService()
private var _REF_BASE = URL_BASE
private var _REF_BARS = URL_BASE.child("data").child("bars")
var REF_BASE: FIRDatabaseReference {
return REF_BASE
}
var REF_BARS: FIRDatabaseReference {
return _REF_BARS
}
}
And my modified viewController file (i did not use a tableViewController)
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
var baruri = [Bar]()
override func viewDidLoad() {
super.viewDidLoad()
myTableView.dataSource = self
myTableView.delegate = self
DataService.ds.REF_BARS.observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print(snap)
if let barData = snap.value as? Dictionary<String, AnyObject> {
let bar = Bar(barData: barData)
self.baruri.append(bar)
print(self.baruri)
self.myTableView.reloadData()
}
self.myTableView.reloadData()
}
self.myTableView.reloadData()
}
self.myTableView.reloadData()
}
)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView( _ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return baruri.count
}
func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.myTableView.dequeueReusableCell(withIdentifier: "newCell", for: indexPath) as! NewCell
var baruriTabel: Bar!
baruriTabel = baruri[indexPath.row]
cell.barNameLBl.text = baruriTabel.name
cell.followersNrLbl.text = String(baruriTabel.followers)
cell.areaLbl.text = baruriTabel.area
cell.addedToFavoritesLbl.text = String(baruriTabel.addedToFav)
cell.happyHourLbl.text = baruriTabel.happyHour
cell.urlLbl.text = baruriTabel.url
cell.lattitudeLbl.text = String(baruriTabel.latitude)
cell.longitudeLbl.text = String(baruriTabel.longitude)
cell.phoneLbl.text = String(baruriTabel.phone)
cell.zipCode.text = String(baruriTabel.zipCode)
return cell
}
}

Send array by segue to new view controller swift iOS 9

I am attempting to send an array of data to a new view controller and I'm currently getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
Im using the API data from www.thecocktaildb.com
Example:
http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita
Not sure what I'm doing wrong. Tried debugging and checking values before the segue in my search view controller and they're accurate.
Heres my code:
Main Storyboard
SearchViewController
class SearchViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var SearchBar: UISearchBar!
var valueToPass:Drinks!
var isSearching : Bool = false
class Drinks {
var idDrink: Int = 0
var strDrink: String = ""
var strCategory: String = ""
var strAlcoholic: String = ""
var strGlass: String = ""
var strInstructions: String = ""
var strDrinkThumb: String = ""
var strIngredient1: String = ""
var strIngredient2: String = ""
var strIngredient3: String = ""
var strIngredient4: String = ""
var strIngredient5: String = ""
var strIngredient6: String = ""
var strIngredient7: String = ""
var strIngredient8: String = ""
var strIngredient9: String = ""
var strIngredient10: String = ""
var strIngredient11: String = ""
var strIngredient12: String = ""
var strIngredient13: String = ""
var strIngredient14: String = ""
var strIngredient15: String = ""
var strMeasure1: String = ""
var strMeasure2: String = ""
var strMeasure3: String = ""
var strMeasure4: String = ""
var strMeasure5: String = ""
var strMeasure6: String = ""
var strMeasure7: String = ""
var strMeasure8: String = ""
var strMeasure9: String = ""
var strMeasure10: String = ""
var strMeasure11: String = ""
var strMeasure12: String = ""
var strMeasure13: String = ""
var strMeasure14: String = ""
var strMeasure15: String = ""
}
var TableData:Array< Drinks > = Array < Drinks >()
override func viewDidLoad() {
super.viewDidLoad()
for subView in self.SearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""))
}
}
}
self.SearchBar.delegate = self
self.TableView.delegate = self
self.TableView.dataSource = self
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if self.SearchBar.text!.isEmpty {
self.isSearching = false
}else{
self.isSearching = true
let userSearchInput = self.SearchBar.text!.lowercaseString
let newString = userSearchInput.stringByReplacingOccurrencesOfString(" ", withString: "%20", options: NSStringCompareOptions.LiteralSearch, range: nil)
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + newString
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
var count = 1
if let drinks = post["drinks"] as? [NSDictionary] {
self.TableData.removeAll()
for drink in drinks {
let adrink = Drinks()
if let strDrink = drink["strDrink"] as? String {
print(String(count) + ". " + strDrink)
adrink.strDrink = strDrink
count++
}
if let strCategory = drink["strCategory"] as? String {
print(" Category: " + strCategory)
adrink.strCategory = strCategory
}
if let strDrinkThumb = drink["strDrinkThumb"] as? String {
print(" Thumbnail Image: " + strDrinkThumb)
adrink.strDrinkThumb = strDrinkThumb
}
self.TableData.append(adrink)
self.TableView.reloadData()
}
}
})
task.resume()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
//title = TableData[indexPath.row].strDrink
cell.textLabel?.text = TableData[indexPath.row].strDrink;
let imageString = TableData[indexPath.row].strDrinkThumb
if (imageString == ""){
let noDrinkImage : UIImage = UIImage(named: "noimage.jpg")!
cell.imageView!.image = noDrinkImage
}else{
let drinkImage = UIImage(data: NSData(contentsOfURL: NSURL(string:TableData[indexPath.row].strDrinkThumb)!)!)
cell.imageView!.image = drinkImage
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
print(TableData[indexPath.row].strDrink)
valueToPass = TableData[indexPath.row]
//self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
}
// hide kwyboard when search button clicked
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchBar.resignFirstResponder()
}
// hide keyboard when cancel button clicked
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchBar.text = ""
self.SearchBar.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
}
}
}
DrinkViewController.swift
class DrinkViewController: UIViewController {
#IBOutlet weak var DrinkNameLabel: UILabel!
var passedValue : SearchViewController.Drinks!
override func viewDidLoad() {
super.viewDidLoad()
DrinkNameLabel.text = passedValue!.strDrink
// 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.
}
}
Do it like this instead
In your didSelectRowAtIndexPath pass the array
self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
Here you need to pass the array to your DrinkViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
// declare myArray in your drinkViewController and then assign it here
// now your array that you passed will be available through myArray
drinkViewController.myArray = sender
}
}
Update
After I got your project I noticed that the issue you had was that you did drag a segue from the tableView to the drinksController directly - what happened is that didSelectRowAtIndexPath will not be called and your sender will always be nil drinkViewController.myArray = sender as! Drinks.
I changed that by dragging the segue from the viewController to the drinksController instead.

Resources