Sorry if this is just a basic concept of Tables in Swift, but I'm quite new to Swift and have spent quite some time trying to figure this out with no luck.
I have an array named 'Data' which is structured like this:
var Data = [
["Alex","25","Male","258475"],
["Sean","29","Male","145737"],
["Grace","34","Female","295049"],
...
]
I'd like to present this in a TableViewController such that each cell contains the name, age, gender and an ID. Most examples that I've found use data structured in a different way:
var Data = [
["Alex","Sean","Grace"],
["25","29","34"],
["Male","Male","Female"],
...
]
Is there a way to use the data structure that I have and present it in rows of a table view? Or would I be better off restructuring my data? Thanks.
As I see it there are a couple of ways you can do this. You could create a struct which contains each person and have an array of those. Somthing like this.
struct Person {
var name: String
var age: String
var gender: String
var id: String
}
Then store your data in an array
var data = [Person]
Then in your table cell you can set up to have a label for each of the items you want to display.
Or a down and dirty way you can get the info you want to show in the defualt cell text area is to concatonate the strings togther as s single string.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath)
var cellText = ""
let row = indexPath.row
for x in data[row]{
cellText = cellText + ", " + x
}
cell.textLabel?.text = cellText
return cell
}
In the above we find the array inside the data array which corresponds to the row number, then we loop through that array adding all the strings together to get 1 big string and then display that string in the table.
Here is a tutorial which gives a good overivew of table views which may help.
https://www.codingexplorer.com/getting-started-uitableview-swift/
Nested multiple arrays as table view data source is the worst choice. Never use those.
The usual and recommended choice is a custom struct.
enum Gender {
case male, female
}
struct Person {
let name, id : String
let age : Int
let gender : Gender
}
let people = [Person(name:"Alex", id: "258475", age: 25, gender: .male),
Person(name:"Sean", id: "145737", age: 29, gender: .male),
Person(name:"Grace", id: "295049", age: 34, gender: .female)]
...
Related
From my server I have a table like this,
objectId parentId id locationName
I am trying to make a treeview under iOS using RATreeView. Every single object(cell) will have its unique id, and every cell that under some other cell will have its parentId which equals to its father's Id. Right now I'm trying to get those data from my server and assemble them as a treeview during runtime. But I really do not have a good algorithm to solve this.
My algorithm is that get all the parentId in an array and id in another array, then find if there is anything equal in two arrays. But this comes with an problem, when there are more than two children under one cell, there will be duplicate parent cell. Anyone has any good idea?
I think it's better if you can get the response like this
objectId, [childrendObjectId] (array of children id) id locationName
You will do it easier.
But if you can't change the response, whenever you want to get the children of the object, just filter it.
I have a simple example here, hope it help
class MyObject {
var id = 1 // I don't know id or objectId is uniqueId, so I remove your objectId, just edit it
var parentId: Int?
var locationName: String?
init(id: Int) {
self.id = id
}
}
var array = [MyObject]()
for idx in 1...100 {
let myObj = MyObject(id: idx)
if idx > 10 {
myObj.parentId = Int(arc4random() % 10 + 1)
}
array.append(myObj)
}
func childrenOf(_ object: MyObject) -> [MyObject] {
return array.filter({$0.parentId == object.id})
}
let firstObject = array[0]
print(childrenOf(firstObject).map({$0.id}))
I have a Computer Science ISP to create a trivia game. I am trying to set a title of a button from an item in a Multi-Dimensional array. The array consists of 22 questions, type String arrays with 6 items in the array.
Looking like this :
let Q1:[String] = ["3","Who invented the telephone?","Rogers","Virgin Mobile","Graham Bell","Nikola Tesla","0"]
I have a shuffled Array that includes all 22 questions(22 Q1-Q22's) and I want a button's title to be the second item in the first array in the shuffledArray. But it gives me this error:
Cannot convert value of type 'Any' to expected argument type 'String?'
Based on the compile error you are getting, I would assume that if you tried to press option and click on shuffledArray, probably, it would be of type [[Any]] (depends on how you are declaring it). If you know that the element should be a String, you could cast it as follows:
if let qLabelText = shuffledArray[0][1] as? String {
qlabel.text = qLabelText
}
But
I would note that:
if you are pretty sure that shuffledArray should be an array of strings array, then you should -somehow- declare it [[String]] instead, thus there is no need to cast the element as string.
However, for such a case, creating your own custom Model for such a case (template) might be a better choice of doing it as a 2D array.
For instance:
struct QuestionModel {
var number: String
var content: String
var answer1: String
var answer2: String
var answer3: String
var answer4: String
var correctAnswer: String
}
Definitely, the structure of declaring the model is based on your requirement and may not be necessary to clone it as is.
You could declare your question as:
let question1 = QuestionModel(number: "3", content: "Who invented the telephone?", answer1: "Rogers", answer2: "Virgin Mobile", answer3: "Graham Bell", answer4: "Nikola Tesla", correctAnswer: "0")
Thus shuffledArray would be an array of QuestionModel ([QuestionModel]) instead of [[String]].
Now, you could write your newQ function as:
func newQ() {
let queestion1 = shuffledArray[0]
qlabel.text = question1.content
button1.setTitle(question1.answer1, for: .normal)
button2.setTitle(question1.answer2, for: .normal)
button3.setTitle(question1.answer3, for: .normal)
button4.setTitle(question1.answer4, for: .normal)
}
Following the above approach would be more expressive and easy to work with.
Pretty new so apologies if this is noobish.
I'm trying to get the key and the value from an associative array to print out as the label text in a cell.
At the moment I have the array:
let users = ["John","James","Liam"]
and I am getting the value for the cell text like so:
cell.textLabel!.text = self.users[indexPath.row]
Which will give me rows of the names in. I am struggling when I add in user ages like so
lets users = ["John" : 36, "James": 12, "Liam": 30]
I get this error:
Ambiguous reference to member 'subscript'
How do I get the cell text to display both the name and age?
If you really need to refer to the data via an array, there are at least two ways you can easily accomplish this. Create a Person object like in the comments, or you can quickly use a tuple structure. The following code works in Xcode Playground (Swift 3, 4).
// - First Approach
struct Person {
var name: String
var age: Int
}
let users = [Person(name: "John", age: 36), Person(name: "James", age: 12), Person(name: "Liam", age: 30)]
// say indexPath.row = 0
print("name: \(users[0].name), age: \(users[0].age)") // name: John, age: 36
// - Second Approach
let usersTuple = [("John", 36), ("James", 12), ("Liam", 30)]
print("name: \(usersTuple[0].0), age: \(usersTuple[0].1)") // name: John, age: 36
You need to define a dictionary and with ages and names and in each cell get from the dictionary the age with the name as key, or you can define a model with name and age like Person and put and use as your datasource Array, which I think is better
class Person{
var age : Int = 0
var name : String = ""
init(name:String,age:Int){
self.name = name
self.age = age
}
}
declare an array of Person in your ViewController
var users = [Person(name: "John", age: 36),Person(name: "James", age: 12),Person(name: "Liam", age: 30)]
In the cellForRow method
let currUser = self.users[indexPath.row]
cell.textLabel!.text = currUser.name + "Age: \(currUser.age)"
If you're coming from a PHP style background, it can be confusing that dictionaries look like associated arrays but there's no way to reference them by index like in PHP. You'll need to reference by the key (the string) or convert them into something which you can retrieve later.
Luckily in Swift you can just use something called a tuple, which looks like this:
let user = ("John", 36)
And you reference the values like this:
let name = user.0
let age = user.1
You can store tuples in arrays, so you can do this:
let users = [("John", 36), ("James", 12)]
let johnAge = users[0].1
You can also give the tuple named parameters but by this point you might as well create a struct. Here's what it looks like anyway:
let user = (name: "John", age: 36)
let johnAge = user.age
Another neat trick with tuples is that if you typealias it you can create it the same way you would a struct, without having to device the properties individually, like this:
typealias User = (name: String, age: Int)
let john = User(name: "John", age: 36)
By this point it's just a case of saving a few lines of code but it really depends on how lightweight you need the user object to be. You wouldn't be able to make it conform to anything in the future, which is why a struct can be a better option. If all you ever need is a lightweight object, tuples are great.
I have three labels in custom tableview; first label I have displayed country array data, in second label I have displayed states array data and in final label I have displayed fruits array data.
In search bar if I search the country I need to filter the regarding country data .
In search bar if I search the state I need to filter the regarding state data.
In search bar if I search the fruit I need to filter the regarding fruit data.
Kindly help me.
let data: [Person] = []
var dataToDisplay: [Person] = []
let searchText = "asd"
dataToDisplay = data.filter { (person: Person) -> Bool in
return person.name!.contains(searchText) || person.lastName!.contains(searchText) || person.dateOfBirth!.contains(searchText)
}
where Person is:
struct Person {
let name: String?
let lastName: String?
let dateOfBirth: String?
}
woodText.text = [String](textForWood.values) This is my code. woodText is a UITextView, and textForWood is a dictionary. Please help.
woodText.text = textForWood["Oak"] as! String
You need to assign a String to the text of a UITextView. The above shows how to extract a String from a Dictionary.
Addition based on the comments
I don't think using a dictionary to populate a table view is a good idea. (Remember, dictionaries are not ordered, arrays are.) You should have an array of some kind that informs the table view how many rows it should display and what to display in those rows.
One solution would be an array of dictionaries ([[String : String]]). You can then populate each cell in cellForRowAtIndexPath. The dictionary for each row should contain something like
["name" : "Oak", "text" : "The text to display in the oak cell..."]
Use the standard boilerplate code to dequeue the cell with the text view and then
let woodDictionary = textForWood[indexPath.row]!
woodText.text = woodDictionary["text"] as! String
It would be much better to use a simple object.
struct Wood {
let name: String
let text: String
}
try this:
var string = ""
for value in textForWood.values.array {
string = string.stringByAppendingString("\(value), ")
}
woodText.text = string
hope this helps.