How to Handle Two Different Types in an Array in Swift for a Uitableview

how to handle two different types in an Array in Swift for a UITableView

Here is an approach that uses a protocol to unite your two classes:

protocol TableItem {

}

class Header: TableItem {
// Header stuff
}

class Item: TableItem {
// Item stuff
}

// Then your array can store objects that implement TableItem
let arr: [TableItem] = [Header(), Item()]

for item in arr {
if item is Header {
print("it is a Header")
} else if item is Item {
print("it is an Item")
}
}

The advantage of this over [AnyObject] or NSMutableArray is that only the classes which implement TableItem would be allowed in your array, so you gain the extra type safety.

Swift - display two different arrays of structs in a table view

Create a protocol with common property with Date type and add it in both structs. In ViewController add an array which merges both array and sorts by date.

Use that array in tableView data source methods.

protocol CommonData {
var date: Date { get }
}
struct A: CommonData, Codable {
var date: Date
var x: String
}
struct B: CommonData, Codable {
var date: Date
var y: String
}
class TimelineViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

var arr1: [A] = []
var arr2: [B] = []
var totalArr: [CommonData] {
return (arr1 as [CommonData]) + (arr2 as [CommonData]).sorted(by: { $0.date < $1.date })
}
override func viewDidLoad() {
super.viewDidLoad()
arr1.append(A(date: Date(), x: "x"))
if let yesterDay = Calendar.current.date(byAdding: .day, value: -1, to: noon) {
arr2.append(B(date: yesterDay, y: "y"))
}
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return totalArr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier")
?? UITableViewCell(style: .default, reuseIdentifier: "reuseIdentifier")
print(totalArr[indexPath.row].date.description)
if let data = totalArr[indexPath.row] as? A {
print(data.x)
} else if let data = totalArr[indexPath.row] as? B {
print(data.y)
}
return cell
}
}

Using two arrays in UITableview swift

Don't do that. Don't use multiple arrays as data source

return list.count + list_2.count

causes the error because actually you have only list.count number of items where list.count must be equal to list_2.count. The addition raises an out-of-range exception at row list.count + 1

Use a custom struct

struct Item {
let foo : String
let bar : String
}

Then map the two arrays

var items = [Item]()

items = zip(list, list_2).map{ Item(foo:$0.0, bar:$0.1) }

In numberOfRowsInSection return items.count

In cellForRowAt get the value from the Item instance

let item = items[indexPath.row]
cell.la_view.text = item.foo
cell.la_view2.text = item.bar

To append an item use

func append(add:Int) {
let lastIndex = items.count
items.append( Item(foo:"\(add)", bar:"\(add)") )
let indexPath = IndexPath(row: lastIndex, section: 0)
table_View.insertRows(at: [indexPath], with: .automatic)
}

And please according to the naming convention use lowerCamelCased rather than snake_cased variable names.

How do I populate two sections in a tableview with two different arrays using swift?

TableView Cells

You could use a multidimensional array. For example:

let data = [["0,0", "0,1", "0,2"], ["1,0", "1,1", "1,2"]]

For the number of sections use:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return data.count
}

Then, to specify the number of rows in each section use:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}

Finally, you need to setup your cells:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellText = data[indexPath.section][indexPath.row]

// Now do whatever you were going to do with the title.
}

TableView Headers

You could again use an array, but with just one dimension this time:

let headerTitles = ["Some Data 1", "KickAss"]

Now to set the titles for the sections:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < headerTitles.count {
return headerTitles[section]
}

return nil
}

The code above checks to see there's a title for that section and returns it, otherwise nil is returned. There won't be a title if the number of titles in headerTitles is smaller than the number of arrays in data.

The Result

Sample Image

How to fill tableview with two arrays using single custom cell?

Hello You not need to add two section just do as bellow.
This is your arrays.

let datalist1 = ["firstCell1" , "firstCell2" , "firstCell3" , "firstCell4"]
let datalist2 = ["secondCell1" ,"secondCell2" , "secondCell3" ,"secondCell4"]

Number of rows

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


return datalist1.coun
}

Cell for row

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as? FirstCell
cell.Lbl1.text = datalist1[indexPath.row]
cell.Lbl2.text = datalist2[indexPath.row]
return cell!
}

Putting different custom cell types in a tableview

This idea from your dequeue call in cellForRowAt is ingenious and natural-seeming, but illegal:

as! cellTypes[indexPath.row]

Swift won't let you cast (as!) to a type that is not specified until runtime. It's a static language, not a dynamic language. The type must be a literal type specified at compile time.

You'll just have to split your cellForRowAt implementation into two completely separate switch cases, one for rows 0 and 1, and one for rows 2 and 3, and do a different dequeue for each one, each one declaring and specifying its own local cell variable with a cast as! FilterTableViewCell or as! FilterTableViewCell2 literally — and proceeding from there, separately, within each case.

You cannot unify the two cases as your elegant-looking code attempts to do, because only in a context where cell is typed literally as FilterTableViewCell or FilterTableViewCell2 can you access the properties belonging to the respective type.

As for this expression:

var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),
FilterTableViewCell2(),FilterTableViewCell2()]

...the problem here is that Swift can only infer that this must be an array of UITableViewCell, which has no FilterTableViewCell properties.

You could work around this by defining a third type, e.g. FilterTableViewCellParent, to act as a common superclass for FilterTableViewCell and FilterTableViewCell2, and giving it their common properties which they can both inherit; reminderCells could then be an array of FilterTableViewCellParent and you'd be able to access the properties through an element of it. (Or of course you could make FilterTableViewCell the superclass of FilterTableViewCell2 or vice versa, and thus do it with just two types.)

But personally I think you should abandon your attempts to be "elegant" and just do everything completely separately in the two cases of the switch, even at the cost of some repetition. Sometimes one must just program the same way Superman gets into his pants; he may be Superman but he still has to get into one leg at a time.

Working with array with different data types in Swift

Use a protocol that has the methods/properties necessary for next and previous actions. Have both of your track types implement the protocol. Have your array have the type of the protocol.

protocol Track {
title: String
albumTitle: String
// other method and properties
}

class JSONTrack: Track {
// implementation
}

class CoreDataTrack: Track {
// implementation
}

let tracks = [Track]()


Related Topics



Leave a reply



Submit