2017-01-04 1 views
1

UIStoryboard의 instantiateViewController(withIdentifier:) 메서드를 사용하여보기 컨트롤러를 인스턴스화 한 후 키워드를 사용하여 다운 캐스트해야하는 이유는보기 컨트롤러의 속성에 액세스 할 수 있도록하기 위해서입니다. UIStoryboard 메서드 instantiateViewController(withIdentifier:)은 이미 UIViewController을 반환하며 스토리 보드 ID을 기반으로하는 클래스를 알고 있거나 이것이 실제로 발생한다고 가정하지만 완전히 사실은 아닙니다.Swift에서 instantiateViewController (withIdentifier :)를 사용한 후 다운 캐스팅이 필요한 이유

다음 코드는 작동하고 컴파일되지만 왜 그 이유를 알고 싶습니다. 문서를 기반으로 이것을 작성하는 경우, 다운 캐스팅이 필요하다고 가정하지 않았으므로 기능에서 반환되는 유형 및/또는 객체와 관련하여 내가 배웠거나 이해하지 못한 부분을 파악하려고합니다.

func test_TableViewIsNotNilOnViewDidLoad() { 

     let storyboard = UIStoryboard(name: "Main", bundle: nil) 

     let viewController = storyboard.instantiateViewController(
      withIdentifier: "ItemListViewController") 

     let sut = viewController as! ItemListViewController 

     _ = sut.view 

     XCTAssertNotNil(sut.tableView) 

    } 
+3

'withIdentifier : "ItemListViewController"는 스토리 보드에서 View Controller의 ID를 참조하고'UIViewController' 클래스 유형을 반환하기 때문에 연관된 UIViewController 클래스를 반환하지 않습니다. 그래서 Down-casting에 의해 Class를 할당합니다. –

+2

그냥 선언문을 읽으십시오! 'func instantiateViewController (식별자 식별자와 함께) -> UIViewController' 아주 간단합니다. – matt

답변

3

storyboard.instantiateViewController... 항상있는 UIViewController (특정 서브 클래스의 기본 클래스)를 반환하므로 따라서는 서브 클래스에 고유의 구현 세부 사항을 알 수 없다.

위에서 언급 한 방법은 스토리 보드 ID를 기반으로 하위 클래스 유형을 추정하지 않습니다. 이는 다운 캐스팅 할 때 코드에서 수행하는 작업입니다 (here 참조). 위의 방법에서 UIViewController를 얻고 다음에 내리 뜬 강제 때문에

func instantiateViewController(withIdentifier identifier: String) -> UIViewController 

그래서 작동하여 ItemListViewController (당신이 UIViewController 서브 클래스로 ItemListViewController을 정의하기 때문에 항상 작동).

추신. 나는 당신의 질문을 이해해 왔는지 확신하지 못합니다, 이것은 매우 직설적입니다.

+0

"이 식별자는 뷰 컨트롤러 객체 자체의 속성이 아니며 스토리 컨트롤러 파일을 찾기 위해 스토리 보드 파일에서만 사용됩니다."라는 오해가 있거나 기본적으로이 라인에서 오해됩니다. 좋아, 나는 배우고있어, 나는 앞으로 나아갈 수 있도록 매우 감사한다. –

1

이 완전히 잘못 스토리 보드 ID

을 기반으로하는 클래스 알고있다. 스토리 보드 ID는 문자열입니다. 귀하의 경우에는 정적 문자열이 발생하지만이 방법은이를 요구하지 않습니다. 그것은 런타임에 계산 될 수 있습니다. (그리고 저는 그것을 개인적으로 작성한 코드를 작성했습니다). 문자열은 클래스 이름과 일치하지만 실제로는 필요하지 않습니다. 식별자는 모든 문자열 일 수 있습니다. 그리고 스토리 보드는 편집 프로세스의 일부가 아닙니다. 스토리 보드는 코드가 컴파일 된 시간과 실행되는 시간 사이에 문제의 오브젝트가 다른 유형으로 쉽게 변경 될 수 있습니다.

컴파일 타임에 클래스를 계산하는 데 충분한 정보가 없기 때문에 컴파일러는 문제가 해결 될 경우 수행 할 작업을 명시 적으로 약속하고 장애가 발생할 경우 수행 할 작업을 결정해야합니다. as!을 사용 했으므로 "잘못된 것으로 판명되면 충돌하십시오."라고 말합니다.

+0

나는 선택의 여지가 있기 때문에 어떤 오류 또는 응용 프로그램 충돌을 피하기 위해 미안보다 더 안전한 방법으로 보인다. 많은 도움이되었습니다. –

1

이해를 돕기 위해 일반적으로 객체 지향 프로그래밍에 대한 배경 지식을 읽어야 할 수도 있습니다. 주요 개념은 클래스, 인스턴스/객체, 상속 및 다형성입니다.

storyboard.instantiateViewController()ItemListViewController의 인스턴스를 만들지 만 UIViewController으로 반환됩니다. 이 부분을 이해하기 어려운 경우 객관적인 지식 기반이 필요한 곳입니다. 예를 들어 C++과 같은 객체 지향 언어 (OO languges)에서는 클래스 (또는 객체라고도 함)의 인스턴스를 부모 (또는 조부모 또는 위대한 부모 등) 클래스에 대한 포인터로 참조 할 수 있습니다. 대다수의 객체 지향에 관한 문헌 및 튜토리얼에서 상속 및 형변환에 대한 개념은 항상 기본 클래스 및 파생 객체에 대한 포인터 등을 사용하여 설명됩니다. 그러나 Swift를 사용하면 다른 많은 OO 언어에서 포인터가 노출되지 않습니다.

코드에서

, 그리고 단순화 된 방법으로이 문제를 설명하고 등은 C했다 ++ 또는 그와 유사한 OO 언어는 OO에있는 대부분의 튜토리얼 일을 설명하는 방법입니다 경우 :

let viewController = storyboard.instantiateViewController(
      withIdentifier: "ItemListViewController") 

viewController 인 " 타입 ItemListViewController의 객체를 가리키는 클래스 유형 UIViewController의 포인터 "

컴파일러는 포인터 viewControllerUIViewController 인 것으로 간주하므로 캐스트를 명시 적으로 수행하지 않는 한 ItemListViewController의 특정 메서드 나 속성에 대해 알지 못합니다.

+0

클래스의 상속을 사용하는 방법을 이해하는 데 100x의 눈을 열었습니다. Apple의 API와 관련하여 사용되었습니다. 많은 도움을 준 –

1

이것은 부분적으로 다형성 때문입니다. 당신이 중 하나 Person 또는 Student 얻을거야 tag 매개 변수의 값에 따라

class Person { 
    let name: String 
} 

class Student: Person { 
    let schoolName: String 
} 

func createRandomPerson(tag: Int) -> Person { 
    if tag == 1 { return Person() } 
    else { return Student() } 
} 

let p = createRandomPerson(2) 

: 예를 들어, 다음 코드를 가져 가라. 당신이 함수에 2를 전달하는 경우

이제, 당신은 createRandomPersonStudent 인스턴스를 반환 할 것을 확신 할 수 있습니다,하지만 당신은 여전히 ​​createRandomPerson 기본 클래스의 인스턴스를 반환 시나리오가로 다운 캐스트해야합니다.

스토리 보드와 마찬가지로 올바른 식별자를 전달하면 예상 한 뷰 컨트롤러를 얻을 수 있지만 사실상 스토리 보드는 UIViewController 서브 클래스 (또는 심지어 UIViewController)의 인스턴스를 만들 수 있기 때문에 토론 할 수있는 기능이 있습니다. 반환 유형은 UIViewController으로 설정됩니다.

마찬가지로 수학을 잘못하면 - 1createRandomPerson()으로 전달하거나 스토리 보드에 잘못된 식별자를 전달하면 예상 한 결과를 얻을 수 없습니다.

+0

이 합법적 인 것처럼 보입니다. 예를 들어 내가 다운 캐스팅 프로세스를 수행하지 않았다고 가정 해 봅시다. 유형을 신속하게 확인할 수없는 경우 유형을 확인하기 위해 변수 문제를 해결하는 데 사용할 수있는 방법이나 이름이 있습니까? 문제 해결을 위해 어떤 유형의 콘솔을 뱉어 낼 수 있습니까? –

+1

'is' 연산자를 통해 확인할 수 있습니다 -'viewController is MyViewController' 또는'if-let'를 통해 :'let castedController = viewController as? MyViewController {좋은 컨트롤러} else {나쁜 컨트롤러}' – Cristik

관련 문제