為什麼 iOS delegate / data source function 的第一個參數常常是它對應的元件
iOS delegate / data source function 的第一個參數常常是它對應的元件,比方以下例子。
- scrollViewDidScroll(_:) 的第一個參數是 scroll view。
optional func scrollViewDidScroll(_ scrollView: UIScrollView)
- tableView(_:didSelectRowAt:) 的第一個參數是 table view。
optional func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
)
- tableView(_:cellForRowAt:) 的第一個參數是 table view。
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell
為什麼 Apple 習慣將這些 function 的第一個參數設計成 delegate / data source 對應的元件呢 ? 它有許多好處,其中一個在於當有多個元件共用同一個 delegate / data source 時,我們可從參數區分判斷做不同的事。
以下我們以奧運 App 為例,如下圖所示,畫面上有 2 個 collection view,分別顯示奧運運動 icon 的小圖和吉祥物的大圖。
2 個 collection view 的 data source 都是 OlympicViewController,因此我們必須在 function collectionView(_:numberOfItemsInSection:) 和 collectionView(_:cellForItemAt:) 判斷對應的 collection view 才能顯示正確的內容。
為了區分不同的 collection view,我們先連接 outlet mascotCollectionView & gameCollectionView。
class OlympicViewController: UIViewController {
@IBOutlet weak var mascotCollectionView: UICollectionView!
@IBOutlet weak var gameCollectionView: UICollectionView!
之後在 data source function 將參數 collectionView 和 outlet 比對,即可決定回傳的 cell 數量和內容。
extension OlympicViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mascotCollectionView {
return mascots.count
} else {
return games.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == mascotCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "\(MascotCollectionViewCell.self)", for: indexPath) as! MascotCollectionViewCell
cell.imageView.image = UIImage(named: "\(mascots[indexPath.item])")
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "\(GameCollectionViewCell.self)", for: indexPath) as! GameCollectionViewCell
cell.imageView.image = UIImage(named: games[indexPath.item])
return cell
}
}
}