Provide tableviewcell with var of an object stored in a array - xcode

i want to do the following thing:
1- Create objects from a class (with 3 variables)
2- Store those objects in a array
3- Create a tableview
4- The cell from the tableview must provide input from the first variable.
I got stuck on the last step. Can anybody help me?
var totalBooks = [AnyObject]() *// create an empty array*
var newBook = Book(setTitle: "booktitle", setWriter: "writer", setFile: "file") *// creates object from a class with 3 variables*
totalBooks.append(newBook) *// puts the object in the array*
*cell.textLabel?.text = totalBooks **???*** *// must put the first variable (setTitle) as output information.*
Thanks in advance

1. You should create the array like this:
let totalBooks = [Book]()
2. setTitle is not a good name of a property - use title
3. Set your totalBooks array as a data source for your table view by conforming to the UITableViewDataSource Protocol.
You can read about it here and try it yourself - UITableViewDataSource
4. In tableView(_:cellForRowAtIndexPath:) set the cell's title label for the corresponding item in your totalBooks data source.

Here is a solution.
Create a property in your view controller var myBooks = [Book]()
In viewDidLoad method
override func viewDidLoad() {
super.viewDidLoad()
for _ in 1...3 {
var newBook = Book(setTitle: "booktitle", setWriter: "writer", setFile: "file")
myBooks.append(newBook)
}
}
In cellForRowAtIndexPath delegate method
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
let book = self.myBooks[indexPath.row]
cell.label.text = book.title //or book.setTitle, whatever you have
return cell
}

Related

Should a View contain the Model it present?

In MVC pattern, should a View contain the Model it is presenting?
For example, I have an Item model, ItemsListView & ItemRowView to display it.
In order to display the list, should I pass the Item model to ItemRowView (1) or I can pass Item.title, Item.details, Item.image, etc to the ItemRowView (2)
In (1), it is violate the MVC design pattern where View does not talk directly to the Model, and the View can also call Model methods
In (2), when make the View dummy, If in another ViewController, we use the ItemsList a gain, we have to duplicate the passing parameters again, and what happend if we need to pass one more properties to the user?
There another way, using ViewModel to wrap around the Model to handle UI Logic, but that will create many classes, and everytime I get a list of models, I also have to map it to ViewModels
example:
class ItemModel {
var name: String = ""
var price: Double = 9000
}
Should I assign the model to UITableViewCell like this: (so the cell can update the data itself whenever new data come)
class ItemTableViewCell: UITableViewCell {
#IBOutlet var titleLabel: UILabel!
var item: ItemModel! {
didSet {
self.updateUI()
}
}
func updateUI() {
titleLabel.text = item.name
}
}
Or should I keep the cell dummy, and do the update UI in ViewController:
class ItemTableViewCell: UITableViewCell {
#IBOutlet var titleLabel: UILabel!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ItemTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ItemTableViewCell", for: indexPath)
var item = items[indexPath.row]
cell.titleLabel.text = item.name
return cell
}
Yes. As it enables you to use the base methods of the model itself instead of creating wrapper classes and handling conversion based on design change.
The Rule of thumb nowadays is to have a view-model for each view if that view requires more than one object.This allows you to handle design and data changes without touching the controller.

Grabbing PFFile and loading in default PFCollectionViewCell

I'm having trouble loading the image in a default PFCollectionViewCell. I'm using the PFQueryCollectionViewController, and has set up the stuff properly - except for the imageFile.
The default PFCollectionViewCell has two fields: the PFImageView and the UILabel.
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFCollectionViewCell? {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as? PFCollectionViewCell
if cell == nil {
cell = PFCollectionViewCell()
}
let nom = object as! Nom
cell?.imageView.file = nom.imageFile
println(nom.imageFile) //prints the object id
cell?.imageView.loadInBackground() //nothing actually loads
cell?.textLabel.text = nom.createdBy.name //textlabel is populated properly
return cell
}
I was able to populate the textField
I wasn't able to populate the imageView
What am I doing wrong?
Figured it out: You need to make sure you also put the placeholder image for it to load. You must set the image property of the PFImageView.
They should really document that...

Save UITableView names to array on button action

I want to save the names that are filled in UITableView to an array
var mineSpillere = [String]()
How can I do this on buttonAction?
This is button action for how i add names to tableview:
#IBAction func addButtonAction(sender: AnyObject) {
mineSpillere.append(namesTextBox.text)
myTableView.reloadData()
}
and also here code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.myTableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel!.text = self.mineSpillere[indexPath.row]
return cell;
}
That only when I press the "back" button in the application, the names from the UITableView will be saved in an array.
I am going to access these names from another view controller also, so i need them to be saved as an array.
Okay so it looks like you have all the data in the mineSpillere array already as you're using cell.textLabel!.text = self.mineSpillere[indexPath.row] so to get that array back to the first view controller. You could use the following code in the view controller that is being presented when the 'back' button is being pressed:
class FirstViewController: UIViewController,SecondViewControllerDelegate {
var mineSpillereCopyFromSecondVC = [String]()
func presentSecondViewController() {
// Im not sure the class name for you're second view
// where the tableView is located.
var secondVC: SecondViewController = SecondViewController();
secondVC.delegate = self
// Also not too sure on how you're presenting the `SecondViewController` so I'm goingg to leave that empty.
// The important part is just above us.
}
func passMineSpillere(mineSpillere: [String]) {
// This class now has the mineSpiller array of name.
self.mineSpillereCopyFromSecondVC = mineSpillere
}
}
And then in you SecondViewController where the tableView is located you could add the following code.
import UIKit
protocol SecondViewControllerDelegate {
func passMineSpillere(mineSpillere:[String])
}
class SecondViewController: UIViewController {
var delegate: SecondViewControllerDelegate?
var mineSpillere = [String]()
// This will be called when the 'back' button is pressed.
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
// Pass the mineSpillere array back to the delegate
// which is the firstViewController instance.
self.delegate?.passMineSpillere(self.mineSpillere)
}
}

Swift displaying passed data from prepareForSegue

Ok, first time I have ever had to ask for help on here, usually I can search and find my answer but not this time. I have a table that displays a pictures and names. If one of them are selected it goes to another view and the data passes. However, I am trying to get that passed information to display in a table like: Name: (Passed Info), Age: (Passed Info), Gender: (Passed Info) etc. I know the data passes because I can display the info in a label, but I can not figure out how to get it to show in a table. Index issue? String Issue?
This is code that passes the info:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController
var horseIndex = appsTableView!.indexPathForSelectedRow()!.row
var selectedHorse = self.horses[horseIndex]
detailsViewController.horse = selectedHorse
This is the code on the controller getting the data where I want the table to display
class DetailsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBOutlet weak var titleLabel: UILabel!
var horse: Herd?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.horse.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.horse[indexPath.Row]
return cell
}
}
I get an error on the return self.horse.count stating not a member and an error on the self.horse[indexPath.Row] stating NSIndex does not have a member named row.
I feel like I am not unwrapping it properly or something, but I can not figure it out or find an answer in my searches. If you need more information please let me know and thanks in advance for any help.
CLARIFYING...
You correctly grab self.horses[horseIndex] in the segue method, so you've already done the work to get the 1 specific horse. No need to do it again. Is self.horses tied to the Herd type? Confusing why Herd shows up again in the DetailView - you don't seem to need it.
It sounds like what you actually want at this point is a tabular layout of the details of that single horse ... Correct? Like going from your entire "Contacts" list to the tabular view of a single contact?
That no longer involves the array of multiple horses, so your use of Herd? and herd.count aren't necessary. Use static labels or a static tableView to show the info from the 1 Horse.
WHAT'S YOUR DATA STRUCTURE & WHAT GOES IN DETAIL VIEW?
Presumably what you want to create (if you haven't already) is a Horse Type:
class Horse {
//you could use optional properties here, or require them for a fully initialized Horse.
let name:String?
let gender:String?
let breed:String?
var age:Int?
var restingHeartRate:Int?
init(name:String?, gender:String?, breed:String?, age:Int?, restingHeartRate:Int?) {
//set arguments passed in to respective properties of self...
}
func winTripleCrown() {
println("\(name!) Wins! Suck on that, Sea Biscuit!")
}
}
Ensure your horses array is declared to only take Horse instances, and fill it appropriately:
var horses = [Horse]()
let horse1 = Horse(name:"Bob" gender:"male" breed: "Yessir, I am a real horse" age:42 restingHeartRate: 30)
horses.append(horse1)
println(horses.count) //prints "1"
horses[0].winTripleCrown() //prints: "Bob Wins! Suck on that, Sea Biscuit!"
Use the Horse Type instead of Herd in the DetailViewController:
var horse: Horse? //nil until set in prepareForSegue
Then in the segue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
...
detailsViewController.horse = selectedHorse
Now, assuming you only put properly created Horse instances into the initial array, and there IS one at the selectedIndex, you're guaranteed that the horse variable in DetailViewController is a Horse instance, and that it's the one selected in the 1st "overall" tableView.
CREATE THE DETAIL VIEW
EASY:
The easy solution at this point is to create a detailView layout with labels, images, etc and hook them up to #properties in the DetailViewController. Then map the Horse properties to the #IBOutlets. Done. No need to mess w/tableViews anymore - just fake it or use a scrollView to make it look like a table.
TABLEVIEW ROUTE
But if you want to use a UITableView, then you'd need the delegate methods like you're using... The difference is you need to look at the # of properties of the single Horse instance - not anything about the overall list of Horses in a Herd or total array.
You COULD hard-code the # of rows if you're certain the # and order of Horse properties will always be consistent:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5 //1 row per property in a `Horse` instance as defined above
}
However, if you want to account for more dynamic results (like an array of wins/losses, or a photo gallery of variable length) you'd need to have enough cells to map all the Horse properties. How can you do that with a custom type that isn't an array or dictionary?
In Swift, you can determine how many properties a Type has by creating a "Mirror" type and using it for introspection, to reflect info back to you like the count property missing above.
let horseMirror = reflect(self.horse)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.horseMirror.count //should also return "5" but no longer hard-coded
}
And then in cellForRowAtIndexPath: you can switch on the indexPath to assign the various Horse properties to the labels (or images, etc) in the tableView cells. Create custom tableView cell types w/unique identifiers if you want to show different information, or stick w/built-in options:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
//haven't played w/this to see if the optionals are correct. Consider it psuedocode...
switch indexPath.row {
case 1: cell.textLabel.text = self.horse.name?
case 2: cell.textLabel.text = self.horse.gender?
case 3: cell.textLabel.text = self.horse.breed?
case 4: cell.textLabel.text = String(self.horse.age?)
case 5: cell.textLabel.text = String(self.horse.restingHeartRate?)
default: cell.textLabel.text = ""
}
return cell
}

Xcode - cellForRowAtIndexpath - initialising cell

What's the difference between this:
var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
And this:
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
They both seem t work fine for me.
PS: I know this seems to be an amateur question but i'm beginner in Xcode, so no reason to be a smug.
When you write :
var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
You are initializing a new cell using its constructor.
And when you write :
var cell = self.tableView.dequeueReusableCellWithIdentifier("cell")
You are dequeuing a cell, so you are assuming your cell with the identifier cell has been already registered in the tableView.
Typically, if the cell was designed in Interface Builder and set as a prototype cell or if you have registered your cell for reuse using the method self.tableView.registerClass(MyCell.classForCoder(), forCellReuseIdentifier: "cell") you won't need to use the constructor because it is already initialized in the tableView.
But if your cell is designed programmatically such as creating UILabel, UIImage or whatever components, you will have to use the constructor instead, and then use the dequeue method.
So, if you have to use the constructor (because you're initializing everything by code) your code will look like this :
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell.cellLabel.text = "Hello world"
cell.cellImage.image = UIImage(named: "funny_cat.jpg")
return cell
}
But if your cell was registered for reuse or if it is a prototype cell you will just have to use
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.cellLabel.text = "Hello world"
cell.cellImage.image = UIImage(named: "funny_cat.jpg")
return cell
}
I think the best place to look how tableview work, you should look the official documentation here : Table View Programming Guide for iOS

Resources