[英]How to display 2 types of cell in 1 TableView Swift 4
I want to display 2 types of cell.Both types of cell is display data from 2 different API call.So the structure is basically like this: 我想显示两种类型的单元格,两种类型的单元格都是显示来自2个不同API调用的数据,因此结构基本上是这样的:
Type A is only appears 1 times which is from API method A ,which is the first cell of the TableView
,the rest of all are Type B which is from API method B . 类型A仅出现1次,是API方法A中的一种 ,它是
TableView
的第一个单元格,其余全部是类型B ,它是API方法B中的 。
In order to make this works,I done the following: 为了使它起作用,我做了以下工作:
1) In StoryBoard,I set the structure of TableView
like so : 1)在StoryBoard中,我像这样设置
TableView
的结构:
MyTableView
-Type A Cell
--My others view..
-Type B Cell
--My others view..
2) Both Cell have their TableViewCell
class. 2)两个Cell都有其
TableViewCell
类。
3) Both Cell have their own model class to initialize the JSON
come from API 3)两个Cell都有自己的模型类来初始化来自API的
JSON
And then finally in my ViewController have all this code: 最后在我的ViewController中拥有所有以下代码:
All the basic code here
//The NSObject class for both type of cell
var typeAArray = [TypeA]()
var typeBAarray = [TypeB]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.getTypeAData()
self.getTypeBData()
}
func getTypeAData(){
//code to call API,parse JSON and also append to `typeAArray`
//and reload TableView
}
func getTypeBData(){
//code to call API,parse JSON and also append to `typeBArray`
//and reload TableView
}
The code for TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return typeAArray.count + typeBArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let typeACell = tableView.dequeueReusableCell(withIdentifier: "TypeACell", for: indexPath) as! TypeATableCell
typeACell.data = self.typeAArray[indexPath.row] //Here I get index or of range error
return typeACell
}
let typeBCell = tableView.dequeueReusableCell(withIdentifier: "TypeBCell", for: indexPath) as! TypeBTableCell
typeBCell.data = self.typeBArray[indexPath.row]
return typeBCell
}
What I get so far: 到目前为止,我得到的是:
Now with the setting and the code above,I get index out of range
error in the part of if indexPath == 0
,and no any data display in the TableView
. 现在有了上面的设置和代码,
if indexPath == 0
,我得到index out of range
错误,并且TableView
没有任何数据显示。
So my question is: 所以我的问题是:
How to make 2 types of tableViewCell appear in 1 single TableView which the data from 2 different API method call? 如何使2种类型的tableViewCell出现在1个单个TableView中,其中2个不同的API方法调用的数据?
Take numberOfSections method and do following: 使用numberOfSections方法并执行以下操作:
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return typeAArray.count
} else {
return typeBArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let typeACell = tableView.dequeueReusableCell(withIdentifier: "TypeACell", for: indexPath) as! TypeATableCell
typeACell.data = self.typeAArray[indexPath.row] //Here I get index or of range error
return typeACell
}
let typeBCell = tableView.dequeueReusableCell(withIdentifier: "TypeBCell", for: indexPath) as! TypeBTableCell
typeBCell.data = self.typeBArray[indexPath.row]
return typeBCell
}
Okay here's what's going on. 好的,这是怎么回事。 Your
numberOfRowsInSection
returns total number of elements from both arrays A and B. Assuming that typeBArray
has loaded faster than typeAArray
, you'll get the total number of items equal to size of typeBArray
. 您的
numberOfRowsInSection
返回数组A和B中元素的总数。假设typeBArray
加载速度快于typeAArray
,则得到的项目总数等于typeBArray
大小。 In cellForRowAt
you assume that item at the row 0 belongs to the first data model, hence you're trying to access typeAArray[0]
while it's still empty and contains no data. 在
cellForRowAt
您假定第0行的项目属于第一个数据模型,因此,您尝试在typeAArray[0]
仍然为空且不包含任何数据的情况下对其进行访问。 This leads to crash. 这导致崩溃。 You need to take the offset into consideration:
您需要考虑偏移量:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < self.typeAArray.count {
let typeACell = tableView.dequeueReusableCell(withIdentifier: "TypeACell", for: indexPath) as! TypeATableCell
typeACell.data = self.typeAArray[indexPath.row]
return typeACell
}
let typeBCell = tableView.dequeueReusableCell(withIdentifier: "TypeBCell", for: indexPath) as! TypeBTableCell
typeBCell.data = self.typeBArray[indexPath.row - self.typeAArray.count]
return typeBCell
}
But honestly, just use sections instead. 但老实说,只是使用部分。
Obvious it should give you an error as your indexPath.row starts with 1 in your data source for TypeBTableCell
and your array elements index starts with 0 for typeBArray
. 显然,它应该给您一个错误,因为在TypeBTableCell的数据源中
TypeBTableCell
以1开头,而TypeBTableCell
的数组元素索引以0 typeBArray
。 So it won't match with each other. 因此,它们将彼此不匹配。
You need to reduce value for indexPath.row
1 step. 您需要减少
indexPath.row
1步骤的值。 Also ensure both arrays have elements in it. 还要确保两个数组都包含元素。
Try this and see: 试试看,看看:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRows = typeAArray.count + typeBArray.count
print("typeAArray.count = \(typeAArray.count)\n")
print("typeBArray.count = \(typeBArray.count)\n")
print("numberOfRows = \(numberOfRows)\n")
return numberOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var indexPathRowForB = max(0, indexPath.row - 1)
if indexPath.row == 0 && self.typeAArray.count > 0 {
let typeACell = tableView.dequeueReusableCell(withIdentifier: "TypeACell", for: indexPath) as! TypeATableCell
typeACell.data = self.typeAArray[indexPath.row]
return typeACell
} else {
print("self.typeAArray.count is zero")
indexPathRowForB = indexPath.row
}
if self.typeBArray.count > 0 {
let typeBCell = tableView.dequeueReusableCell(withIdentifier: "TypeBCell", for: indexPath) as! TypeBTableCell
typeBCell.data = self.typeBArray[indexPathRowForB]
return typeBCell
} else {
print("self.typeBArray.count is zero")
// return UITableviewCell instance from here......
}
}
Firstly have an array that stores all the data returned from API method A and B , instead of having 2 separate arrays which can make things a bit more complex but make sure your type A is the first item in in the array. 首先有一个数组,该数组存储从API方法A和B返回的所有数据 ,而不是拥有2个单独的数组,这可能会使事情复杂一些,但要确保类型A是数组中的第一项。
Then something like this: 然后是这样的:
var tableViewDataArray = [Array]()
var typeAArray = [Array]()
var typeBArray = [Array]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.getTableViewData()
}
func getTableViewData() {
let queue = DispatchQueue(label: "com.company.app.queue")
let group = DispatchGroup()
group.enter()
queue.async(group: group) {
getTypeAData()
group.leave()
}
queue.async(group: group) {
getTypeBData()
group.leave()
}
group.notify(queue: queue) {
group.wait()
tableViewDataArray.append(typeAArray)
tableViewDataArray.append(typeBArray)
self.tableView.reloadData()
}
}
func getTypeAData() {
let urlRequest: NSURLRequest = ...
let task = self.session?.dataTaskWithRequest(urlRequest, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
// parse your response and append to array
self.typeAArray.append(response)
})
}
func getTypeBData() {
let urlRequest: NSURLRequest = ...
let task = self.session?.dataTaskWithRequest(urlRequest, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
// parse your response and append to array
self.typeBArray.append(response)
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableViewDataArray.count
}
public final func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customObject = tableViewDataArray[indexPath.section]
if indexPath.row == 0 &&
customObject is TypeAObject {
if let typeACell = tableView.dequeueReusableCell(withIdentifier: TypeACell.identifier, for: indexPath) as? TypeACell {
// do any databinding here
typeACell.customObject = customObject
return typeACell
}
} else if customObject is TypeBObject {
if let typeBcell = tableView.dequeueReusableCell(withIdentifier: TypeBCell.identifier, for: indexPath) as? TypeBCell {
// do any databinding here
typeBcell.customObject = customObject
return typeBcell
}
}
return UITableViewCell()
}
Note: This was done is Playground but should hopefully give you a better idea of what to do. 注意:这是在Playground完成的,但希望可以为您提供一个更好的方法。 You should also become familiar with GCD and executing async taks sequentially or concurrently (refer to these tutorials from RayWenderlich: part 1 and part 2 )
您还应该熟悉GCD并依次或同时执行异步任务(请参阅RayWenderlich的这些教程: 第1 部分和第2部分 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.