I'm trying to load the items of an array into a UITableView in a Swift iOS App.
ViewController.swift
import UIKit
class ViewController: UIViewController {
let website = MyWebsite()
let authenticated = ViewAuthenticated()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func getData(_ sender: Any) {
var arrayTEST = self.website.getArray() //["red", "green", "blue"]
self.authenticated.data = arrayTEST //["red", "green", "blue"]
let viewAuth = self.storyboard?.instantiateViewController(withIdentifier: "ViewAuthenticated") as! ViewAuthenticated
self.present(viewAuth, animated: true)
}
}
ViewAuthenticated.swift
import UIKit
class ViewAuthenticated: UIViewController, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
public var data: [String] = ["123", "456", "789"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier")!
let text = data[indexPath.row]
cell.textLabel?.text = text
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
What I would like to do is creating a UITableView containing the items sent by ViewController.
I think the problem is that in ViewAuthenticated the UITableView is created before ViewController sends his new array (["red", "green", "blue"]).
How can I solve this?
You should set the array of values to data property of ViewAuthenticated View, before presenting the view.
#IBAction func getData(_ sender: Any) {
var arrayTEST = self.website.getArray() //["red", "green", "blue"]
self.authenticated.data = arrayTEST //["red", "green", "blue"]
let viewAuth = self.storyboard?.instantiateViewController(withIdentifier: "ViewAuthenticated") as! ViewAuthenticated
viewAuth.data = self.authenticated.data
self.present(viewAuth, animated: true)
}
And remove the hardcoded data array value. Change it to :
var data: [String] = []
Simple solution, the authenticated controller is not needed at all:
let authenticated = ViewAuthenticated()
...
#IBAction func getData(_ sender: Any) {
let viewAuth = self.storyboard?.instantiateViewController(withIdentifier: "ViewAuthenticated") as! ViewAuthenticated
viewAuth.data = self.website.getArray() //["red", "green", "blue"]
self.present(viewAuth, animated: true)
}
Related
Ive been stuck trying to pass data from the FoodEatenController(FEC) Footer to the TotalCaloriesController. The code that I have now it shows NOTHING in the calorieLbl of the TotalCalorieController(TCC).
The delegate that ive been using to pass the data from the FEC to the TCC does not pass the text/string data that is in the FoodFooter calorieTotallbl to the TEC calorieLbl
the data that populates the cells of the FEC is retrieved from Cloud Firestore and passed in from anotherView Controller (FoodPickerController)
import UIKit
class FoodEatenController: UIViewController{
var selectedFood: FoodList! // allows data to be passed into the VC
// allows data to be sepearted into sections
var foodItems: [FoodItem] = []
var groupedFoodItems: [String: [FoodItem]] = [:]
var dateSectionTitle: [String] = []
#IBOutlet weak var tableView: UITableView!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TotalCalorieController {
}
}
}
extension FoodEatenController: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return dateSectionTitle.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let date = dateSectionTitle[section]
return groupedFoodItems[date]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foodCell = tableView.dequeueReusableCell(withIdentifier: "FoodCell") as! FoodCell
let date = dateSectionTitle[indexPath.section]
let foodItemsToDisplay = groupedFoodItems[date]![indexPath.row]
foodCell.configure(withCartItems: fooditemsToDisplay.foodList)
return foodCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let foodHeader = tableView.dequeueReusableCell(withIdentifier: "FoodHeader") as! FoodHeader
let headerTitle = dateSectionTitle[section]
foodHeader.dateLbl.text = "Date: \(headerTitle)"
return foodHeader
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let foodFooter = tableView.dequeueReusableCell(withIdentifier: "FoodFooter") as! FoodFooter
let date = dateSectionTitle[section]
let arrAllItems = groupedFoodItems[date]!
var total: Float = 0
for item in arrAllItems {
let eaten = item.productList
let selectedMeal = item.foodList.selectedOption
if selectedMeal == 1 {
total = total + (Float(eaten!.calorie))
}
}
foodFooter.calorieTotal.text = String(subtotal!)
foodFooter.delegate = self
return foodFooter
}
}
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
popUp.calorieLbl.text = info
}
}
import UIKit
protocol EatenFoodDelegate: class {
func onTouchCaloireInfo(info: String)
}
class FoodFooter: UITableViewCell {
weak var delegate: EatenFoodDelegate? = nil
#IBOutlet weak var calorieTotal: UILabel!
#IBOutlet weak var totalInfoBtn: UIButton!
#IBAction func totalOnClicked(_ sender: AnyObject) {
self.delegate?. onTouchCaloireInfo(info: calorieTotal.text!)
}
}
class TotalCalorieController: UIViewController, EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
calorieLbl.text = info
}
#IBOutlet weak var calorieLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func returnButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
print("Close Taxes and Fees")
}
}
Add the following line at the end of the func onTouchCaloireInfo(info:)
self.present(popUp, animated: true, completion: nil)
If you would like to be sure that the function onTouchCaloireInfo(info:) gets called, just add the following line:
debugPrint("onTouchCaloireInfo")
And check, if it prints the given string in the console of the Xcode
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
debugPrint("onTouchCaloireInfo")
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
self.present(popUp, animated: true) {
popUp.calorieLbl.text = info
}
}
}
I am new in programming, and have problem. I am using parse for my array in tableview. When the row is selected i want to segue on another view controller to textView. The tableview works good but i can't get text to textView.
tableVC:
import UIKit
import Parse
class ThirdTableVC: UITableViewController {
#IBOutlet weak var refresherQuotes: UIRefreshControl!
#IBOutlet var quoteTable: UITableView!
var selectedQuote: PFObject?
var quoteItems = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func updateQuotesResults(_ sender: UIRefreshControl) {
fetchQuotesData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadQuoteTexts(selectedQuote: selectedQuote)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return quoteItems.count
}
func fetchQuotesData() {
let quotesQuery = PFQuery(className: "TotalTest")
quotesQuery.whereKey("Subcategory", equalTo: selectedQuote ?? nil)
quotesQuery.findObjectsInBackground { (objects, error) in
if let realCategoryObjects = objects {
self.quoteItems = realCategoryObjects
self.tableView.reloadData()
self.refresherQuotes.endRefreshing()
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let quoteCell = tableView.dequeueReusableCell(withIdentifier: "quoteCell", for: indexPath)
let quoteItem = quoteItems[indexPath.row]
let quoteUserTitle = quoteItem.object(forKey: "TextQuote") as? String
quoteCell.textLabel?.text = quoteUserTitle
return quoteCell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQuoteDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let quoteobject = quoteItems[indexPath.row] as? NSDate
let quoteController = (segue.destination as! UINavigationController).topViewController as! DetailViewController
quoteController.detailItem = quoteobject
quoteController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
quoteController.navigationItem.leftItemsSupplementBackButton = true
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row tapped: \(indexPath.row)")
let selectedQuotes: PFObject = quoteItems[indexPath.row]
let FourthVC = self.storyboard?.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
FourthVC.fourthTextView.text = quoteItems[indexPath.row] as? String
self.navigationController?.pushViewController(FourthVC, animated: true)
}
func loadQuoteTexts(selectedQuote: PFObject!) {
let quoteQuery = PFQuery(className: "TotalQuote")
quoteQuery.whereKey("QuoteSubs", equalTo: selectedQuote ?? nil)
quoteQuery.includeKey("QuoteSubs")
quoteQuery.findObjectsInBackground { (result: [PFObject]?, error) in
if let searchQuoteResults = result {
self.quoteItems = searchQuoteResults
self.quoteTable.reloadData()
}
}
}
}
How can I change this?
viewController with textView:
import UIKit
import Parse
class FourthViewController: UIViewController {
var getQuote: PFObject?
#IBOutlet weak var fourthTextView: UITextView!
#IBOutlet weak var fourthLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
fourthLabel.text! = getQuote as! String
fourthTextView.text! = getQuote as! String
}
}
Please help me to passing texts
If you use pushViewController do it like that , in did selectRowAt
let MainStory: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = MainStory.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
and now pass your text
desVC.getText = "here goes your text u want to pass"
FourthViewController
set up your var
var getText = String()
so you can finally use
self.navigationController?.pushViewController(desVC, animated: true)
so it will pass all parameters you previous add with desVC.getSomething
in FourthViewController you just need to use getText.
The problem is that you are changing from a view to another with pushViewController, by doing that your prepareForSegue won't be executed.
On your didSelectRow you need to call performSegue(withIdentifier:sender:).
You can lookup this question for more information on how to do it.
I get the following error after passing data from one ViewController to another.
no data
eventStruct(title: What are we gonna do today?, date: 2017-07-13, location: House3, description: Hello beautiful people!)
2017-06-15 22:01:05.697 RUC-App 1.0[48760:5792168] Warning: Attempt to present <RUC_App_1_0.EventViewController: 0x7fb686636460> on <RUC_App_1_0.NewsfeedViewController: 0x7fb68662e6a0> whose view is not in the window hierarchy!
The code from the first ViewController:
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class NewsfeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var ref:DatabaseReference!,
posts = [eventStruct]()
#IBOutlet weak var tableview: UITableView!
var propertStruct : (Any)? = nil
override func viewDidLoad() {
super.viewDidLoad()
loadNews()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loadNews() {
ref = Database.database().reference()
ref.child("events").queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
if let valueDictionary = snapshot.value as? [AnyHashable:String]
{
let title = valueDictionary["Title"]
let location = valueDictionary["Location"]
let date = valueDictionary["Date"]
let description = valueDictionary["Description"]
self.posts.insert(eventStruct(title: title, date: date, location: location, description: description), at: 0)
self.tableview.reloadData()
}
})
}
///////////////////////// Table View Content \\\\\\\\\\\\\\\\\\\\\\\\\\
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].title
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].location
let label3 = cell.viewWithTag(3) as! UILabel
label3.text = posts[indexPath.row].date
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "showDetails"){
let secondViewController = segue.destination as? EventViewController
secondViewController?.data = sender as? eventStruct
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: posts[indexPath.row])
}
/////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
}
struct eventStruct {
let title: String!
let date: String!
let location: String!
let description: String!
}
The code of the second ViewController:
import UIKit
class EventViewController: UIViewController {
var data: eventStruct?
#IBOutlet weak var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print (data ?? "no data")
self.titleLabel.text = self.data?.title
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You should not have both triggered and manual segues happening at the same time.
Try this:
Delete your didSelectRowAt function (or comment it out), and replace prepare() with:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "showDetails"){
let secondViewController = segue.destination as? EventViewController
if let idx = tableView.indexPathForSelectedRow {
secondViewController?.data = posts[idx.row]
}
}
}
I have two view controllers 1st name is ViewController and 2nd Name is ContactVC. I have 3 buttons on 1st viewcontroller when i click on a button open 2nd viewController. In 2nd view controller i open phone contacts when i select any contact that contact name should be set as a button title. I have done with 1st button but from 2nd and 3rd button it does not works. Below is the code of 1st ViewController
import UIKit
import ContactsUI
class ViewController: UIViewController,CNContactPickerDelegate {
#IBOutlet weak var con1: UIButton!
#IBOutlet weak var con2: UIButton!
#IBOutlet weak var con3: UIButton!
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.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Contact1Segue"
{
(segue.destination as! ContactVC).delegate = self
}
else if segue.identifier == "Contact2Segue"
{
(segue.destination as! ContactVC).delegate = self
}
else if segue.identifier == "Contact3Segue"
{
(segue.destination as! ContactVC).delegate = self
}
}
func findContacts() -> [CNContact]
{
let store = CNContactStore()
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactImageDataKey,
CNContactPhoneNumbersKey] as [Any]
let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
var contacts = [CNContact]()
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { ( contact, stop) -> Void in
contacts.append(contact)
})
}
catch let error as NSError {
print(error.localizedDescription)
}
return contacts
}
func contactPickerDidCancel(picker: CNContactPickerViewController)
{
print("Cancel Contact Picker")
}
}
extension ViewController: ContactVCDelegate
{
func updateData(data: String)
{
self.con1.setTitle(data, for: .normal)
self.con2.setTitle(data, for: .normal)
self.con3.setTitle(data, for: .normal)
}
}
Below is the 2nd ViewController Code
import UIKit
import ContactsUI
class ContactVC: UIViewController, CNContactPickerDelegate, UITableViewDataSource, UITableViewDelegate {
var contacts = [CNContact]()
var Name:String?
var delegate: ContactVCDelegate?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
DispatchQueue.global(qos: .background).async
{
let a = ViewController()
self.contacts = a.findContacts()
OperationQueue.main.addOperation
{
self.tableView!.reloadData()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
print("Count:\(self.contacts.count)")
return self.contacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchRID", for: indexPath)
return cell
}
else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "CellRID", for: indexPath)
let contact = contacts[indexPath.row] as CNContact
cell.textLabel!.text = "\(contact.givenName) \(contact.familyName)"
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("section:\(indexPath.section), row:\(indexPath.row)")
let allcontact = self.contacts[indexPath.row] as CNContact
Name = allcontact.givenName + allcontact.familyName
self.delegate?.updateData(data: Name!)
print("Name:\(Name)")
_ = self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
}
//MARK:- CNContactPickerDelegate Method
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
contacts.forEach({contact in
for number in contact.phoneNumbers
{
let phonenum = number.value as CNPhoneNumber
print("NUmber is = \(phonenum)")
}
})
}
}
protocol ContactVCDelegate
{
func updateData(data: String)
}
Update your protocol:
protocol ContactVCDelegate
{
func updateData(buttonId:int, data: String)
}
Have a field in your second view controller with buttonId.
And set this value while preparing segue:
(segue.destination as! ContactVC).buttonId = 1
Your Update function:
func updateData(buttonId:int, data: String)
{
switch(buttonId){
case 1:
self.con1.setTitle(data, for: .normal)
break
case 2:
self.con2.setTitle(data, for: .normal)
break
case 3:
self.con3.setTitle(data, for: .normal)
break
}
}
In second view controller, onDidSelect:
self.delegate?.updateData(buttonId:buttonId,data: Name!)
I have a program written in Swift 3, that grabs JSON from a REST api and appends it to a table view.
Right now, I'm having troubles with getting it to print in my Tableview, but it does however understand my count function.
So, I guess my data is here, but it just doesn't return them correctly:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, HomeModelProtocal {
#IBOutlet weak var listTableView: UITableView!
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
var feedItems: NSArray = NSArray()
var selectedLocation : Parsexml = Parsexml()
override func viewDidLoad() {
super.viewDidLoad()
self.listTableView.delegate = self
self.listTableView.dataSource = self
let homeModel = HomeModel()
homeModel.delegate = self
homeModel.downloadItems()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "BasicCell"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: Parsexml = feedItems[indexPath.row] as! Parsexml
myCell.textLabel!.text = item.title
return myCell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedItems.count
}
override func viewDidAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Are you by any chance able to see the error that I can't see?
Note. I have not added any textlabel to the tablerow, but I guess that there shouldn't be added one, when its custom?
Try this code:
override func viewDidLoad() {
super.viewDidLoad()
print(yourArrayName.count) // in your case it should be like this print(feedItems.count)
}