iOS-SOPT-iNNovation / iOS_Traning

18 stars 0 forks source link

<4주차> 하나의 View Controller 코드에서 여러 TableView Controller 역할을 해야 할 경우 어떻게 구분해서 구현해야 하는지 설명하시오. #18

Closed namsoo5 closed 3 years ago

khyunjiee commented 3 years ago

첫번째 방법

UITableViewDelegate, UITableViewDataSource 등의 처리에서 if문 또는 switch문을 이용해서 테이블뷰를 분기처리해준다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableView == table1{
        ...
    } else if tableView == tablew {
      ...
    }
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    switch tableView {
      case table1:
        ...
      case table2:
        ...
      default:
        ...
    }
}

두번째 방법

TableView 별로 클래스를 따로 정의한다.

class FirstTableView: NSObject, UITableViewDataSource, UITableViewDelegate {
  var array1 = Array<Any>()

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
  {
      return array1.count
  }
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
  {
      let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as UITableViewCell
      cell.textLabel?.text = array1[indexPath.row] as? String
      cell.backgroundColor = UIColor.yellow
      return cell
  }
}

class SecondTableView: NSObject, UITableViewDataSource, UITableViewDelegate {
  var array2 = Array<Any>()

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
  {
      return array2.count
  }
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
  {
      let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as UITableViewCell
      return cell
  }
}
self.table1.dataSource = FirstTableView()
self.table1.delegate = FirstTableView()
self.table2.dataSource = SecondTableView()
self.table2.delegate = SecondTableView()
namsoo5 commented 3 years ago

TableView를 구분하는 방법

=== 연산자 이용

==는 값을 비교하는것 ===는 두 인스턴스의 포인터의 참조값을 비교하기 때문에 더 정확


class ViewController: UIViewController {
    var table1: UITableView!
    var table2: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        table1 = makeTableView(frame: CGRect(x: 0, y: 0, width: 375, height: 200))
        table2 = makeTableView(frame: CGRect(x: 0, y: 250, width: 375, height: 200))
        view.addSubview(table1)
        view.addSubview(table2)
    }

    func makeTableView(frame: CGRect) -> UITableView {
        let tableView = UITableView(frame: frame)
        tableView.dataSource = self
        return tableView
    }
}

extension ViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView === table1 {
            return 5
        }
        return 3
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
        cell.backgroundColor = .brown
        return cell
    }
}

DataSource 클래스 만들어주기

UITableViewDataSource를 채택한 인스턴스를 만들고 적용시켜주는 방식

class ViewController: UIViewController {
    var table1: UITableView!
    var table2: UITableView!
    let aDataSource = ATableController()

    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        table1.dataSource = aDataSource
    }
        ...
}

class ATableController: NSObject, UITableViewDataSource {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
        cell.backgroundColor = .red
        return cell
    }
}
dongminyoon commented 3 years ago
  1. TableViewDatasource 프로토콜을 채택한 ViewController 내에서 tableView의 인스턴스를 직접 비교해서 각각의 데이터를 분기하는 방식

  2. DataSource 커스텀 클래스를 여러 개 만들어서 각각 tableView datasource에 대입하는 방식

choidam commented 3 years ago
  1. tableview 이름으로 구분
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
   if tableView == table1 {
        return cell
   } else {
        return cell
   }
}
  1. tag 으로 구분
    override func viewDidLoad() {
        super.viewDidLoad()
        table1.tag = 1
        table2.tag = 2
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
    if tableView.tag == 1 {
        return cell
    } else {
        return cell
    }
    }
iJoom commented 3 years ago
  1. tableview를 각각 선언해서 구분하는 방법
    
    extension SwitchingViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

// ==값비교 , === 인스턴스 주소 비교 if( tableView === self.tableView){ return 3 } if ( tableView === tableView2) { return 10 }

    return 0 // 기본 return값 지정해주지 않으면 error

}

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

}


2. 다른 클래스를 만들어서 DataSource와 Delegate를 채택시킨다.

```swift
override func viewDidLoad(){
 tableView.dataSource = self
//기존처럼 기존의 뷰컨에서 DataSource를 받아서 처리 
tableView2.dataSource = subDataSource
//DataSource를 채택한 sub클래스를 만들어서 사용
}

class subTableViewDataSource: NSObject, UITableViewDataSource {

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

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

}
elesahich commented 3 years ago
  1. 우선 스크롤에 조심하겠다
  2. DataSources를 tableView별로 분기칠 것 같다
  3. Rx는 DataSoruce를 공유할수도 있고 아닐수도 있다
let tableView1 = UITableView()
let tableView2 = UITableView()

Observable.from(["1234","2345"])
      .asObservable()
      .bind(to: tableView1.rx.items) {
                ~
      }

Observable.from(["1234","2345"])
      .asObservable()
      .bind(to: tableView2.rx.items) {
                ~
      }

이렇게 하면 하나의 뷰컨에서도 예쁘게 적용 가능할것 같다

cell의 Size는 아래처럼 TableViewDelegate에서 분기쳐서 나눠주거나

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if tableview == tableView1 {

        }
        else {

        }
    }

아니면 아예 클래스파일을 두개 둘 것 같다 (delegate 클래스를 따로 지정)

5anniversary commented 3 years ago

테이블뷰에서 제공하는 메소드에서 tableView를 이용해 비교해 구분할수가 있습니다.

간단한 예시!

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableView == 첫번째 테이블뷰 {
        return 첫번째 테이블 뷰 에 해당하는 셀
   } else {
        return 두번째 테이블 뷰 에 해당하는 셀
  }
}
Juhyeoklee commented 3 years ago

DataSouce나 Delegate 의 구현 함수에는 첫번째 parameter를 해당 메소드를 호출한 객체가 들어오게 된다. 따라서 다음과 같이 switch 문, if 문을 통해 분기처리를 하여 해당 동작을 구현해 줄 수 있다.

 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch collectionView {
        case productFunctionCV:
            return productFunctionCVExtensionData?.count ?? 0
        case naverLowestPriceInfoCV:
            return naverLowestPriceInfoCVExtensionData?.count ?? 0
        default:
            return 0
        }
    }

그 다음으로 직접적으로 UITableView의 Delegate나 DataSource 등을 채택한 다른 클래스를 구현하는 방법이다. 이 프로토콜들은ㄴ NSObject Protocoal의 상속을 받기 때문에 이 것들을 채택하여 사용하기 위해서는 NSObject에 대한 상속이 필요하다.

따라서

// MARK: - ProductFunctionCVExtension
class ProductFunctionCVExtension : NSObject, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{

    var data: [EfficacyName]?

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        …
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        …
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        …
    }
}

다음과 같이 구현해 준 다음 해당 테이븗 뷰와 컬렉션뷰의 델리게이트와 데이터소스를 해당 뷰컨트롤러가 아닌 해당 객체에 위임하여 사용할 수 있다.

self.productFunctionCV.delegate = self.productFunctionCVExtension
self.productFunctionCV.dataSource = self.productFunctionCVExtension