2017-12-28 54 views
1

참고 :이 게시물은 다시 게시 된 것입니다. 며칠 전에 sans-code와 같은 질문을 올렸습니다. 일부 관련 스 니펫을 추가하기 위해 질문을 편집했지만 질문이 다시 열리지 않았으므로 여기서 다시 게시합니다. 이것이 적절한 방법이 아니라면 알려주십시오!프로그래밍 방식으로 UITableView 컨트롤에서 전환하십시오.

두 가지 모드가있는 응용 프로그램이 있으며 각 모드 (하나의 추가 섹션 하나, 행 수 차이, 다른 UserDefaults 키 등)마다 설정 화면이 약간 다릅니다. 과거에는 switch와 if 문을 사용하여 이것을 구현했지만 더 보수적으로 만들려고 노력하면서 두 모드를 별도의 클래스로 분리하는 방법을 조사했습니다. 처음에는 두 개의 개별 하위 클래스를 만드는 것을 고려했지만 스토리 보드 등에서 어떻게 작동하는지 생각하는 데 어려움을 겪고있었습니다. 나는 두 개의 별개의 서브 클래스 인 UITableView을 사용하여 모드를 기반으로 보여줄 서브 클래스를 viewDidLoad으로 선택하려고했습니다.

그러나이 방법에 문제가 있습니다. 컨트롤러의 cellForRow 메서드가 TableView의 cellForRow 메서드를 호출하도록 설정 했으므로 문제가 발생합니다. dequeueReusableCell을 시도 할 때 앱이 그 라인에서 애매한 "EXC_BAD_INSTRUCTION"오류로 인해 충돌합니다.

여기에 몇 가지 관련 코드는 다음과 같습니다

ViewController.swift

... 
override func viewDidLoad() 
{ 
    super.viewDidLoad() 

    ... 

    tableView = SRScaleSettingsTableView() 
} 
... 
override func tableView(_ tableView: UITableView?, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
{ 
    return (tableView?.cellForRow(at: indexPath))! 
} 

SRScaleSettingsTableView.swift

override func cellForRow(at indexPath: IndexPath) -> UITableViewCell? 
{ 
    ... 
     switch indexPath.section 
     { 
     case 0: 
      ... 
      let switchCell = dequeueReusableCell(withIdentifier: "SwitchCell") as! SRSwitchCell  
      ^Debugger breaks on that line with EXC_BAD_INSTRUCTION 
      ... 

      return switchCell 
     ... 
     } 
} 

어떤 아이디어이를 원인이 무엇에? 나의 접근법조차 정확한가? 이 작업을 수행하는 더 좋은 방법이 있습니까? 감사!

답변

1

단일 UITableView 클래스 (UITableView를 전혀 서브 클래스 할 필요가 없을 가능성이 높음)와 단일 UIViewController 하위 클래스를 유지할 수 있습니다. UITableViewDataSource 프로토콜을 구현하는 두 가지 클래스를 만들고 (가능하면 UITableViewDelegate도)이 두 클래스는 앱이 실행하는 데 필요한 다른 모드에 대해 완전히 다른 방식의 다양한 대표/데이터 소스 방법 (예 : cellForRowAtIndexPath, numberOfRowsInSection, didSelectRow)를 구현할 수있다.

protocol SettingsSource: UITableViewDelegate, UITableViewDataSource { 
} 

class SettingsSourceForModeA: NSObject, SettingsSource { 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)... 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)... 
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)... 
} 

class SettingsSourceForModeB: NSObject, SettingsSource { 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)... 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)... 
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)... 
} 

class SettingsViewController: UIViewController { 
    @IBOutlet tableView: UITableView! 

    var source: SettingsSource! { 
     didSet { 
      tableView.dataSource = source 
      tableView.delegate = source 
     } 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // whatever logic is appropriate to determine the mode 
     if appIsRunningInModeA() { 
      source = SettingsSourceForModeA() 
     } else { 
      source = SettingsSourceForModeB() 
     } 
    } 
} 

위의 코드의 핵심 세부 사항은이다 source SettingsViewController의 변수 - source의 값은 앱이 어떤 모드에서 실행되고 있는지에 기반하며 테이블보기의 데이터 소스로 사용할 클래스를 결정합니다.

스토리 보드 설정은 간단합니다. 하나의 장면 SettingsViewController와 해당 장면의 단일 재고 UITableView입니다.

위의 SettingsViewController은 UITableViewController가 아닌 UIViewController 하위 클래스이므로 데이터 소스 및 대리자 프로토콜은 별도의 클래스로 구현되고 런타임에 결정되므로주의해야합니다. 이를 위해서는 스토리 보드의 tableView 콘센트를 수동으로 연결해야합니다. 그러나 UITableView의 dataSource를 연결하고 스토리 보드에 아울렛을 위임하지는 않습니다. 대신, 위의 샘플 코드와 같이 런타임에 완료됩니다.

위의 예제 코드에서 UITableViewDelegate 및 해당 메서드에 대한 참조를 무시할 수있는 경우 UITableViewDelegate를 구현할 필요가 없습니다. 또는 UITableViewDelegate 구현 (예 : didSelectRow 메소드)이 앱이 실행할 수있는 두 가지 모드에 대해 동일하면 뷰 컨트롤러 클래스에서이를 구현할 수 있습니다.이 경우 delegate 콘센트를 연결할 수 있습니다. 스토리 보드의보기 컨트롤러에 직접 테이블보기.

0

UITableView와 UITableViewController가 함께 작동하는 방법에 대한 오해가 있습니다. UITableView는 기본 데이터 (섹션 수, 행 수 및 실제 셀 수 등)에 대한 세부 정보를 제공하기 위해 UITableViewDataSource가 필요합니다. 이것은 UITableViewController가 수행하는 작업 (UITableViewDataSource를 준수 함)입니다. 그래서 당신이 tableFor에 대한 cellForRow를 호출하면 데이터 소스 cellForRow 메서드를 호출하여이를 얻습니다.

이렇게하면 코드에서 return (tableView? .cellForRow (at : indexPath))!

테이블보기는 UITableViewController 인 데이터 소스를 호출하고 테이블보기 cellForRow 등을 호출합니다. 방금 본 오류가 발생하여 결국 제거되는 재귀 루프를 입력했습니다.

당신의 전반적인 접근 방식에 관해서는 두 개의 UITableViewController 경로를 따라 가면서 서로 다른 로직을 분리하고 이해하고 유지 보수하는 것이 더 쉬우 며 재사용도 더 쉽게 할 수 있습니다.

스토리 보드에서 작동하는 방법은 두 가지 모드를 전환하는 방법에 크게 달려 있지만 본질적으로 두 컨트롤러를 전환 할 수 있습니다.