Swift display entire array on textview or label - ios

I am working on a cookbook app and I thought I had the knowledge to get the last bit up and running and I have run into a snag. I am trying to get my ingredients array to display on a text field and I cannot get it to work. I have done some research and I have tried a few different things and all of them come up with different errors. I have left them in the code but commented them out so maybe someone looking at it could see what I was doing wrong with what I had going. My code looks as follows for my view controller that will display the ingredients.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ingredients: UITextView!
#IBOutlet weak var directions: UITextView!
var recipe : Recipe!
// var ingredientText = String()
// let separator = (" / ")
override func viewDidLoad() {
super.viewDidLoad()
self.title = recipe.name
directions.text = recipe.directions
// let ingredientsText = separator.join(recipe.ingredients)
// label.text = ingredientsText
// for ingredient: String in recipe.ingredients {
// ingredientsText.join("%#\n", ingredient)
// }
// label.text = ingredientText
// label.text = recipe.ingredients
// var multiLineString = join("\n", recipe.ingredients)
// label.text = multiLineString
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
this is the table VC
import UIKit
class tableVC: UITableViewController {
var recipes: [Recipe] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Juicing Recipes"
let recipe0: Recipe = Recipe()
recipe0.name = "Number 1"
recipe0.ingredients = ["Pasta","Pasta Sauce","Hamburger"]
recipe0.directions = "Cook pasta to directions on box, brown hamburger, add sauce to hamburger, dump on pasta"
recipes.append(recipe0)
let recipe1: Recipe = Recipe()
recipe1.name = "Number 2"
recipe1.ingredients = ["all kinds of stuff","Then a dash of salt"]
recipe1.directions = "enjoy"
recipes.append(recipe1)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipes.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
let recipe: Recipe = recipes[indexPath.row]
cell.textLabel?.text = recipe.name
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
let destCon : ViewController = segue.destinationViewController as! ViewController
destCon.recipe = recipes[indexPath.row]
}
}
then the recipe class
class Recipe: NSObject {
var name = String()
var ingredients = [String]()
var directions = String()
}
It's another one of those things I know it something simple that I am overlooking but I have been stumped on this for a while.

Related

Not able to display values in another viewcontroller from TableView in Swift

I want to display the details of one one table row onto another viewController. But it shows an error saying ' fatal error: unexpectedly found nil while unwrapping an Optional value'
The code for my VC is as follows:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate,UITableViewDataSource, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var nameForUser: UITextField!
#IBOutlet var loginButton: UIButton!
#IBOutlet var tableView: UITableView!
let allEvents = Events.allEvents
var nextScreenRow: Events!
override func viewDidLoad() {
super.viewDidLoad()
//nameForUser.text! = "Please Enter Name Here"
// Do any additional setup after loading the view, typically from a nib.
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.text = ""
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allEvents.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventsCell")!
let event = self.allEvents[indexPath.row]
cell.textLabel?.text = event.eventName
cell.imageView?.image = UIImage(named: event.imageName)
cell.detailTextLabel?.text = event.entryType
//cell.textLabel?.text = allEvents[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
nextScreenRow = allEvents[indexPath.row]
performSegueWithIdentifier("tryToConnect", sender:self)
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.allEvents.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let sec = collectionView.dequeueReusableCellWithReuseIdentifier("eventsSec", forIndexPath: indexPath) as! GridCollectionViewCell
let event = self.allEvents[indexPath.row]
sec.imageView.image = UIImage(named: event.imageName)
sec.caption.text = event.entryType
return sec
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("tryToConnect2", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "successfulLogin"){
segue.destinationViewController as! TabController
//let userName = nameForUser.text
//controller.userName = userName
}
else if (segue.identifier == "tryToConnect"){
let dest = segue.destinationViewController as! DetailedEventViewController
dest.deatiledEvent.text = nextScreenRow.eventName
dest.eventType.text = nextScreenRow.entryType
dest.imageView.image = UIImage(named: nextScreenRow.imageName)
}
}
#IBAction func loginButtonWhenPressed(sender: UIButton) {
let userName = nameForUser.text
if userName == "" {
let nextController = UIAlertController()
nextController.title = "Error!"
nextController.message = "Please enter a name"
let okAction = UIAlertAction(title: "okay", style: UIAlertActionStyle.Default) {
action in self.dismissViewControllerAnimated(true, completion: nil)
}
nextController.addAction(okAction)
self.presentViewController(nextController, animated: true, completion: nil)
}
}
}
When I run this, it shows the error. I have also assigned the delegates for the table view. The code for 'DetailedEventVC' is:
import UIKit
class DetailedEventViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var deatiledEvent: UILabel!
#IBOutlet weak var eventType: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Why does it show that the values are nil?
Help would be greatly appreciated.
Thanks in advance.
The 'EventsDetails.swift' file which has the details of events are a structure. Is there anything wrong in the way I'm calling the values?
import Foundation
import UIKit
struct Events {
let eventName: String
let entryType: String
let imageName: String
static let EventKey = "NameKey"
static let EntryTypeKey = "EntryType"
static let ImageNameKey = "ImageNameKey"
init(dictionary:[String : String]) {
self.eventName = dictionary[Events.EventKey]!
self.entryType = dictionary[Events.EntryTypeKey]!
self.imageName = dictionary[Events.ImageNameKey]!
}
}
extension Events {
static var allEvents: [Events] {
var eventsArray = [Events]()
for d in Events.localEventsData(){
eventsArray.append(Events(dictionary: d))
}
return eventsArray
}
static func localEventsData()-> [[String: String]] {
return [
[Events.EventKey:"Metallica Concert in Palace Grounds", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"Metallica"],
[Events.EventKey:"Saree Exhibition in Malleswaram Grounds", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"SareeExhibition"],
[Events.EventKey:"Wine tasting event in Links Brewery", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"WineTasting"],
[Events.EventKey:"Startups Meet in Kanteerava Stadium", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"StartupMeet"],
[Events.EventKey:"Summer Noon Party in Kumara Park", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"SummerNoonParty"],
[Events.EventKey:"Rock and Roll nights in Sarjapur Road", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"RockNRollNight"],
[Events.EventKey:"Barbecue Fridays in Whitefield", Events.EntryTypeKey: "Paid Entry", Events.ImageNameKey:"BBQFriday"],
[Events.EventKey:"Summer workshop in Indiranagar", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"SummerWorkshop"],
[Events.EventKey:"Impressions & Expressions in MG Road", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"ImpressionAndExpression"],
[Events.EventKey:"Italian carnival in Electronic City", Events.EntryTypeKey: "Free Entry", Events.ImageNameKey:"ItalianCarnival"]
]
}
}
Create properties in your destination viewController and use them like below
import UIKit
class DetailedEventViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var deatiledEvent: UILabel!
#IBOutlet weak var eventType: UILabel!
var myImage = UIImage?
var eventDetails = ""
var typeOfEvent = ""
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = myImage
deatiledEvent.text = eventDetails
eventType.text = typeOfEvent
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
and then in your first viewController you can access them like
let dest = segue.destinationViewController as! DetailedEventViewController
dest.eventDetails = nextScreenRow.eventName
dest.typeOfEvent = nextScreenRow.entryType
dest.myImage = UIImage(named: nextScreenRow.imageName)

Passing value from struct array with segue : index out of range

Hopefully this will be the last question i need to ask!
I have been looking into this for 48 hours now and i still cannot find answers.
Here is the code i am using:
DataSource.swift:
struct Game {
var name : String
var cheats : [Cheat]
}
struct Cheat {
var name : String
var code : String
var desc : String
}
GameListViewController.swift
import Foundation
import UIKit
class GameListViewController: UITableViewController {
var gamesArray = [Game]()
var cheatsArray = [Cheat]()
override func viewDidLoad() {
super.viewDidLoad()
gamesArray = [Game(name: "Game1", cheats: [Cheat(name: "cheat1", code: "code1", desc: "desc1")])]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gamesArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell!
cell.textLabel?.text = gamesArray[indexPath.row].name
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
let DestViewController = segue.destinationViewController as! CheatListViewController
var DataPass : Cheat
DataPass = cheatsArray[indexPath.row]
DestViewController.cheatnameArray = DataPass.name
var DataPass2 : Cheat
DataPass2 = cheatsArray[indexPath.row]
DestViewController.cheatcodeArray = DataPass2.code
var DataPass3 : Cheat
DataPass3 = cheatsArray[indexPath.row]
DestViewController.cheatdescArray = DataPass3.desc
}
}
CheatListViewController.swift
class CheatListViewController: UITableViewController {
var cheatcodeArray = String()
var cheatnameArray = String()
var cheatdescArray = String()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
When i select "Game 1" from gamesArray i instantly receive an index out of range error from the first instance of "DataPass".
I have structured my datasource in this way so that i do not have to edit arrays separately and keep my objects neat and tidy.
If someone could point me in the right direction i would be forever grateful !
Kind regards
Rory
For me it looks like you haven't populated your cheatsArray variable with any cheats. That's why you receive an index out of range exception.
From your code it is a bit hard to understand what you're looking to achieve, but I think I have it..
Notice I use an optional binding to unwrap the destinationViewController, this is safe because any other segue performed will also trigger the same prepareForSegue.
if let destViewController = segue.destinationViewController as? CheatListViewController {
let indexPath : NSIndexPath = self.tableView.indexPathForSelectedRow!
var game = gamesArray[indexPath.row]
destViewController.cheatnameArray = game.cheats.map({ $0.name })
destViewController.cheatcodeArray = game.cheats.map({ $0.code })
destViewController.cheatdescArray = game.cheats.map({ $0.desc })
}
Change your arrays to actual string arrays and not strings..
var cheatcodeArray = [String]()
var cheatnameArray = [String]()
var cheatdescArray = [String]()
The Basics

How do I prepare for segue to load different arrays in my TableViewController?

After days of struggling I can't figure out how to fix this. I am making a simple restaurant app. The foodMenuController contains 2 buttons which have to load different menu arrays into a tableViewController (lunch,breakfast). To define what menu should be loaded I was told by someone to use a variable -> contentMode.
In my TableViewController i set the contentMode to "0". In my foodMenuController i used prepare for segue with a identifier to set the contentMode to 1 (breakfast) and 2 (lunch).
Now the problem is that my table does not know when it is in contentMode 1 or 2 nor do I know where and how to write the code to indicate the table to load different arrays when in a certain contentMode. I hope someone can help me with the code i published below.
import UIKit
class foodMenuController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let foodMenuController = segue.destinationViewController as! foodTableViewController
if segue.identifier == "showBreakfast" {
foodMenuController.contentMode = 1
} else if segue.identifier == "showBakery" {
foodMenuController.contentMode = 2
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
import UIKit
class foodTableViewCell: UITableViewCell {
#IBOutlet weak var foodItem: UILabel!
#IBOutlet weak var foodDescription: UILabel!
#IBOutlet weak var foodPrice: UILabel!
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
}
}
import UIKit
class foodTableViewController: UITableViewController {
// Content Mode Selection in menu
var contentMode = 0
// THIS SHOULD BE LOADED WHEN CONTENT MODE is "1" --> BREAKFAST
var foodItems = ["Bread", "Coffee", "Nada"]
var foodInfo = ["Good", "Nice", "Nothing"]
var foodPrice = ["$1", "$100", "$12,40"]
// THIS SHOULD BE LOADED WHEN CONTENT MODE IS "2" --> LUNCH
var foodItems = ["Not bread", "Not Coffee", "Something"]
var foodInfo = ["Not good", "Not nice", "Yes"]
var foodPrice = ["$1", "$100", "$12,40"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foodItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! foodTableViewCell
cell.foodItem.text = foodItems[indexPath.row]
cell.foodDescription.text = foodInfo[indexPath.row]
cell.foodPrice.text = foodPrice[indexPath.row]
return cell
}
}
Change the array names as shown below.
// THIS SHOULD BE LOADED WHEN CONTENT MODE is "1" --> BREAKFAST
let breakfastItems = ["Bread", "Coffee", "Nada"]
let breakfastInfo = ["Good", "Nice", "Nothing"]
let breakfastPrice = ["$1", "$100", "$12,40"]
// THIS SHOULD BE LOADED WHEN CONTENT MODE IS "2" --> LUNCH
let lunchItems = ["Not bread", "Not Coffee", "Something"]
let lunchInfo = ["Not good", "Not nice", "Yes"]
let lunchPrice = ["$1", "$100", "$12,40"]
var foodItems: [String] = []
var foodInfo: [String] = []
var foodPrice: [String] = []
Now check the value of contentMode in ViewWillAppear
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
switch (contentMode){
case 1:
foodItems = breakfastItem
foodInfo = breakfastInfo
foodPrice = breakfastPrice
case 2:
foodItems = lunchItem
foodInfo = lunchInfo
foodPrice = lunchPrice
default:
break
}
tableView.reloadData()
}
This will copy the desired item, info ,price arrays into the foodItem, foodInfo and foodPrice arrays. The rest of your code will work fine and the UITableView will be populated as desired.

Swift label not displaying what the selected cell says

I have a tableview that is populated with information from a JSON array. I want to make each selected cell segue into a viewController, and in that viewController I have a label the should display what the selected cell says. For example if my cell says California, when I click on the cell it'll open up my viewController and the label would say California.
Seems simple enough, and I've done this before successfully, however this time I'm using JSON to populate my tableView and I'm guessing I'm doing something wrong. With the code posted below, when I click on a cell the titleLabel doesn't even show up.
(My tableView file and DetailsViewController file are posted below, any other swift file I used can be found in my previous question populating Tableview with a function that uses SwiftyJSON)
import UIKit
class EarthTableViewController: UITableViewController {
var info = [AppModel]()
func getEarthquakeInfo(completion: (results : NSArray?) ->Void ){
DataManager.getEarthquakeDataFromFileWithSuccess {
(data) -> Void in
let json = JSON(data: data)
if let JsonArray = json.array {
for appDict in JsonArray {
var ids: String? = appDict["id"].stringValue
var title: String? = appDict["title"].stringValue
var time: String? = appDict["time"].stringValue
var information = AppModel(idEarth: ids, title: title, time: time)
self.info.append(information)
completion(results: self.info)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
getEarthquakeInfo { (info) in
self.tableView.reloadData()
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell
let infoArray = self.info
cell.textLabel!.text = self.info[indexPath.row].title
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "SEGUE" {
let vc = segue.destinationViewController as DetailsViewController
let cell = (sender as UITableViewCell)
let title = cell.textLabel!.text
vc.titleData = title
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return info.count
}
}
My DetailsViewController file:
import UIKit
class DetailsViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var idLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
var titleData: String!
var idData: String!
var timeData: String!
override func viewDidLoad() {
super.viewDidLoad()
var earthInfo = EarthTableViewController()
var getEarthInfo: () = earthInfo.getEarthquakeInfo { (info) in
println("\(info)")
}
titleLabel.text = titleData
idLabel.text = idData
timeLabel.text = timeData
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Passing parameters to the next ViewController with TableView

[This code working very well] This is my situation: I have 2 view controllers, and the second must have TableView. In first view controller i have label and button, when I pressed him, he put me to the second view.Also i passing, when button was pressed: 2 parameters - current time, and another time, which was counted since the program was compile. And my problem is how to put this two parameters to tableView. It must work similar to MasterDetailApplication, where when you press + button it's create a Date in tableView. In my program it must create Date and time when i pressed button and go to the next ViewController. This is my code :
//Parameters.swift
import Foundation
struct Parameters {
let toPass : String
let toPass2: String
}
//SecondViewController
import UIKit
class SecondViewController: UIViewController {
var timer = NSTimer()
var counter = 0
#IBOutlet weak var labelCounter: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true
labelCounter.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(1,target:self, selector: Selector("update"),userInfo: nil, repeats :true)
}
func update(){
labelCounter.text = String(++counter)
if counter == 15 {
timer.invalidate()
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
if (segue.identifier == "segueTest") {
var transfer = segue.destinationViewController as TableViewController
transfer.toPass = labelCounter.text
transfer.toPass2 = "\(formatter.stringFromDate(NSDate()))"
}
}
}
//TableViewCOntroller
import UIKit
class TableViewController: UITableViewController {
#IBOutlet weak var label1: UILabel!
var toPass: String!
var toPass2: String!
var objects = [Parameters]()
override func viewDidLoad() {
super.viewDidLoad()
self.objects = [Parameters(toPass: toPass2, toPass2: toPass)]
// self.view.backgroundColor = UIColor(red :184.0, green: 219.0, blue: 243.0)
// self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as UITableViewCell
var param : Parameters
param = objects[indexPath.row]
cell.textLabel.text = param.toPass
cell.detailTextLabel?.text = param.toPass2 + " sec"
return cell
}
}
But I have another problem: when I put my button, and when I move to the tableViewController, how to do that my 2 parameters will be saved and stay in that tableViewController? When I close the app, this parameters are lost. How could I save them?

Resources