I am rewriting one of my apps in Swift, that displays live weather data for South Kohala. Love Swift so far!
I'm having one small problem that is holding things up. I have a tab bar based app, iPad only.
One of my tabs is a UIViewController with a TableView added to it in the storyboard to display NOAA forecasts. I have a data class Data that retrieves the list from our server and creates a constant List in viewDidLoad. It is an array of arrays with four strings in each subarray.
I have verified that it's there, as I can create a constant: List[0] and println all the strings.
However, when I go to use it to populate the table view, I get a "Use of unresolved identifier" error. If instead, I try setting the cell Title to "Test" that works OK.
This seems like a scope issue, but as the constant is created within the class, I just don't understand why it's not visible in the tableView function. I've looked at dozens of posts on this, but nothing I have found seems to help. Here is the code:
import UIKit
class ForecastsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var forecastsTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let instanceofData: Data = Data()
let list = instanceofData.forecastsList() as NSArray
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
var forecastList:NSArray = list[indexPath.row] //selects one of the arrays from List
cell.textLabel?.text = forecastList[0] as string
return cell
}
It is because List is purely local to the inside of viewDidLoad; where you've declared it, other methods cannot see it.
Contrast, for example, forecastsTable, which is declared outside any method, which means that any method can see it.
This behavior is called "scope" and is crucial to any programming language. Variables declared inside a method are neither visible outside it nor do they persist when that method has finished running. Thus, in your example, not only is List not visible when cellForRowAtIndex runs, it doesn't even exist when cellForRowAtIndex runs - it has been destroyed long before.
Related
I have had a custom collection view and everything worked fine. I wanted to include 'Gemini' to make beautiful animations when sliding my cells horizontally. I believe that the problem is not Gemini, I think the same would have happen with changing VC class to any other one, but I dont know how to solve this because I never faced with this before, is there a shortcut from this?
I have installed and imported the pod into code.
I had a UICollectionViewController but to work with gemini I needed to connect my collectionView from Storyboard to ViewController. Before that, I have put a class in Storyboard for my CollectionView to be GeminiCollectionView like in the image below:
After that, I changed a class for my CollectionView in ViewController, too, like in the image below and got those three errors:
In the later code, it doesnt show any errors:
viewDidLoad
collectionView.gemini
.rollRotationAnimation()
.degree(45)
.rollEffect(.rollUp)
cellForItemAt
self.collectionView.animateCell(cell)
scrollViewDidScroll
self.collectionView.animateVisibleCells()
willDisplay cell
if let cell = cell as? RatingCell {
//RatingCell inhertis the GeminiCell class
self.collectionView.animateCell(cell)
}
So, all the code is fine except the declaration as I mentioned at the beginning and here:
#IBOutlet var collectionView: GeminiCollectionView!
Waiting for random guys to unvote this :P
Solved
#IBOutlet var collectionView: GeminiCollectionView!
That line was a problem. Seems like you mustn't default Swift's name to override mutable property, which is collectionView for Collection Views and tableView for Table Views.
I changed that line to
#IBOutlet var collView: GeminiCollectionView!
...and the errors disappeared.
I have a UITableViewController with its own class HomeVC, containing multiple Cells, one of which uses its own class NewsFeedCell. This cell contains a vertical UIScrollView that displays pics. I want the user to, when he clicks the the row, trigger a segue to a VC with the picture. I created a currentPage variable in NewsFeedCell class, which obviously shows which page, and which picture, is the UIScrollView showing.
In the HomeVC, i have this:
class HomeVC: UITableViewController {
(...)
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
(...)
if indexPath.row == 0 { //The cell containing the UIScrollView
print(NewsFeedCell.currentPage) // I used "print" to simply the shown code
}
}
}
The problem is that xcode gives me an error saying Instance member "currentPage" cannot be used on type "NewsFeedCell".
I tried printing the value of currentPage to the console in the code of NewsFeedCell, and it worked.
Btw, the variable is declared inside the NewsFeedCell and has its first value assigned under awakeFromnNib() to 0, and the second time under:
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
currentPage = Int(floor((scrollView.contentOffset.x - cellWidth / 2) / cellWidth)) + 1
print(currentPage)
}
Please HELP!
It sounds like you created currentPage as an instance variable, meaning that each object of type NewsFeedCell has its own version. To access it, you have to have a reference to an individual NewsFeedCell, like this:
var myCell = NewsFeedCell()
print(myCell.currentPage)
and its value will be different for every cell. If you want there to be only a single currentPage for all NewsFeedCells, you declare it as static, like this (in the NewsFeedCell class):
static var currentPage: Int = 0
then you can access it using NewsFeedCell.currentPage as you have been.
The reason you were able to print(currentPage) from a function inside of NewsFeedCell is that that function is an instance method. Each instance has its own copy, and it prints the currentPage for the specific instance that the method was called on.
It's not quite clear to me what exactly you're trying to do with currentPage, so I'm not sure whether you want a static variable or an instance variable. In general, if you want there to be a single version of the variable that's accessible from anywhere, make it static. If you want each cell to have its own value, make it a regular instance variable.
I've been learning table views from tutorials on YouTube. I was following every step told in the video, and did everything the same as the author of this tutorial, but for some reason I got a strange error - I've heard that it's about old version of Xcode used in the tutorial - I'm working on the latest one.
Debugger tells that "CustomCell" is undeclared.
Every help will be appreciated!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfCwiczenia.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("Cell") as CustomCell
let person = arrayOfCwiczenia[indexPath.row]
cell.setCell(cwiczenia.nazwa, imageName: cwiczenia.obrazek)
return cell
}
CustomCell looks to be a subclass of UITableViewCell
Looks like they left out the part where you need to create it
Create a new file called CustomCell and make sure it's base class is UITableViewCell
You must have a file where you define the behaviour of the custom cell - if that's not called 'CustomCell' then it won't be declared.
Just make sure that you have the same name when you define the class and when you use it.
I would suggest looking at Apple's walkthrough on how to implement a table view. It has step by step instructions with pictures. If you scroll down the the Design Custom Table Cells section I think you will be able to see how to link the custom cell to a file properly
Your tutorial should have mentioned all the details, but here it goes...
You need to define a subclass of UITableViewCell named CustomCell:
import UIKit
class CustomCell: UITableViewCell
{
// Your custom properties/methods.outlets/etc.
}
(typically, in a source file named CustomCell.swift, but this is not compulsory)
If you are using a storyboard, you need to set the class of your prototype cells to "CustomCell" in the identity inspector (third tab from the left on the right inspector pane - the one with the icon that looks like a newspapaer):
Also, In the attributes inspector (fourth tab from the right, icon looks like a slider), set the cell's identifier (in the case of your code, "Cell"):
If you are not using a storyboard, you need instead to register the custom cell class and identifier programmatically:
func viewDidLoad()
{
tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "Cell")
// other setup...
}
I had this same error. Tried cleaning and building which worked but the main issue seemed to just be saving the CustomCell which then becomes recognised by the compiler and removes the error.
Its not limited to cells I've had it with other custom classes before as well. Good one to know about though!
I've just started to use Swift as a prorgamming language and i've run into a problem with Custom cells.
When i try to create custom cells, and then go forward and try to design them the way i need them ( with Style set to Custom ) everything looks good. Now i don't know how to put specific data into them, since all tutorials i found used the style option "basic" where they only have a text label to which they assign their data.
Now for me, when i "control drag" my labels into my code, i give them specific names such as "dateLabel" or "sourceLabel" in order to insert the data correctly.
now i'm not sure, and couldn't find any answers that worked, on how to recall my custom made labels so that i can assign my data to them...
Maybe someone of you could help me with this, since i'm pretty sure it's a simple problem but i coudln't find any resources to this ^^
hopefully the font isn't to small, i just wanted you guys to see the erros i get.
I used the following tutorial as a guide line, since it was the only one that worked just the way this guy did it: https://www.youtube.com/watch?v=0qE8olxB3Kk
I checked the identifier and he is set correctly and i can't find anything online on how i have to properly refer to my own labels with their correct names.
any help would be appreciated :)
Try the following steps:
Create a custom table view cell class that extends UITableViewCell. In my example, the custom table view cell class is called MyCustomTableViewCell.
Update your storyboard's cell so that it uses your custom table view cell class. Go to the Identity Inspector and set the Class value to the name of your custom table view cell class.
Update your storyboard's cell and give it a reuse identity value. Go to the Attributes Inspector and set the Identifier value. For example, I gave my cell an Identifier value of MyCustomCell.
Control drag the cell's labels into your new custom table view cell class (i.e., the MyCustomTableViewCell class).
Once you have done the above steps, you will be able to access the labels when you dequeue your cell in the tableView:cellForRowAtIndexPath: method. As the code snippet below shows, you will need to: 1) get the cell using the reuse identifier you established in the steps above and 2) cast to your custom table view cell class.
For example, here's what your custom table view cell would look like if you named it MyCustomTableViewCell. This is after you created the class and control dragged your labels into this class.
class MyCustomTableViewCell: UITableViewCell {
#IBOutlet weak var categoryLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var sourceLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
}
Your ViewController could look like this:
// NOTE: I subclassed UITableViewController since it provides the
// delegate and data source protocols. Consider doing this.
class ViewController: UITableViewController {
// You do NOT need your UILabels since they moved to your
// custom cell class.
// ...
// Omitting your other methods in this code snippet for brevity.
// ...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Use your cell's reuse identifier and cast the result
// to your custom table cell class.
let article = tableView.dequeueReusableCellWithIdentifier("MyCustomCell", forIndexPath: indexPath) as! MyCustomTableViewCell
// You should have access to your labels; assign the values.
article.categoryLabel?.text = "something"
article.dateLabel?.text = "something"
article.sourceLabel?.text = "something"
article.titleLabel?.text = "something"
return article
}
}
I'm trying to do the opposite of what most people on this topic are asking to do. Most people want a button within a table view cell to call a method in their VC / VC table. I already have a protocol doing that.
Problem / Question
What I am trying to add now is the opposite: I need a button press on my main ViewController (which houses my table) to call a method within my CusomTableViewCell class (note: the button pressed on the main VC is not in the table). I have the protocol class created and the function written, but I don't know how to set the CustomCellViewClass as the delegate. When I did the opposite, I inserted "cell.delegate = self" into the cellForRowAtIndexPath method. I've also used prepareForSegue to assign a delegate. But with no segue and now cell-creation-method, I'm lost!
Example of Desired Function
My end goal is that pressing a button that is in the main VC will change the title of a button within the cells. A simple example would be that I have one view with a single table, on button press the table contents switch between two arrays, cars and motorcycles. When the table is showing cars, the cell button titles should all read "Look inside" but when showing the motorcycle button it should read "Look closer".
Code
I've already written the function that I want the cell to execute:
func cellButton_Title_Switch (currentList: String) {
if vcState == "cars" {
cellButton.setTitle("Look inside", forState: UIControlState.Normal)
}
else {
cellButton.setTitle("Look closer", forState: UIControlState.Normal)
}
}
I created the protocol:
protocol delegateToChangeCellBut {
func cellButton_Title_Switch (currentList: String)
}
I have the self.delegate.cellButton_Title_Switch(currentList) within my VC button and the protocol added to my custom cell class declaration. But how do I do that last missing piece in the custom cell class, where I assign the class to the delegate?
My original problem was that my UITableView's cell has buttons and labels, some of which change to match the state of things outside the table, things handled by the mainViewController.
The custom cell is defined by a customCellviewController. All the custom cell buttons and labels have their IBOutlets connected to the customCellviewController. I couldn't figure out how to make an action/change outside the table (in the mainViewController) immediately cause the cell labels and buttons to change.
Note: Protocols tend to work they other way around (a cell action triggers a function in the mainVC). I couldn't figure out how to use a protocol to solve this. Luckily, the solution was much simpler than a protocol.
The Solution!
I wrote the "updateCell" method that would change the labels and buttons and that code now sits in the customCellviewController. Then I called/triggered the "updateCell" function from the mainViewController simply by adding the call into my cellForRowAtIndexPath function. So it looks something like this:
var stateOfPage = "Green"
//Creates the individual cells. If the above function returns 3, this runs 3 times
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Setup variables
let cellIdentifier = "BasicCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! customCell
cell.updateCell(stateOfPage)
return cell
}
Now the above code/method runs when the table gets built. So to update the cells, have some button tap or other action reload the table data:
tableView.reloadData()
Good luck.