prepare(for:sender:)
메서드 이용결론
Swift에 존재하는 타입의 인스턴스는 생성과 초기화가 이니셜라이저에 의해 보장되므로 테스트하지 않아도 된다. 반면init?()
과 같은 실패 가능한 이니셜라이저는 테스트 대상이다.
유닛 테스트를 학습하면서 어떤 것이 테스트의 대상이 되는지 고민했습니다. 예를 들어 타입의 인스턴스가 성공적으로 생성되었는지를 확인하는 것도 하나의 테스트라고 생각했었지요. 유닛 테스트 번들에서 아래와 같이 테스트해보았습니다.
// MARK: - Person class
class Person {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
// MARK: - Test method for initailizing person class
func testInitializingPerson_whenNameAndAgeAreGiven_hasGivenNameAndAge() {
let ryan: Person = Person(name: "Ryan", age: 3)
XCTAssertEqual(ryan.name, "Ryan")
XCTAssertEqual(ryan.age, 3)
}
결과는 당연히 성공! 이때까지 저는 당연한 것은 없다고 생각하고 모든 것을 테스트해야 한다고 생각했습니다. 하지만 코드 리뷰를 받고 init?()
과 같은 실패 가능한 이니셜라이저가 아니라면 이니셜라이저 자체를 테스트하지는 않아도 된다는 결론을 얻었어요.
리뷰 내용:
음.. 스위프트 인스턴스의 가장 큰 장점 중 하나는 init이 되면 인스턴스의 생성과 초기화가 보장된다는 것이에요. 그래서 아예 init에 대해서는 검증할 필요가 없습니다.
init? 등에 대해서는 검증할 필요가 있겠지만, init 자체에는 테스트 하지 않아도 됩니다.
Swift 언어 가이드의 Initialization 내용을 보면 왜 그런지 나와있을 것 같아요.
그러면 바로 찾아봐야죠!
Source: The Swift Programming Language (Swift 5.4) - Initialization
공식 문서 Initialization
문서에 있네요. 생성된 새로운 인스턴스가 최초에 사용되기 전에 올바르게 이니셜라이즈(초기화)하는 것이 이니셜라이저의 역할이라고 하고 있습니다.
화면을 이동할 때 이전 화면에서 가지고 있던 데이터를 다음 화면으로 넘겨주어야 하는 경우가 있습니다. 이럴 때는 어떤 방법을 적용할 수 있을까요?
TableView
에서 개별 Cell
을 선택했을 때 상세 화면으로 전환되는 과정에서 데이터를 넘겨주는 상황을 예시로 들어보겠습니다.
TableView
를 보여주는 과정에서 TableView
를 담당한 ViewController
가 이미 TableView
와 다음 화면인 상세 화면에서 보여주어야할 정보를 모두 가지고 있습니다 (JSON 디코딩 데이터).
그렇다면 저희가 다음 ViewController
에게 알려주어야 할 정보는 아래와 같습니다.
2. 선택된 Cell
의 indexPath.row
에 따라 보여주어야 할 상세 화면의 데이터 (이름, 이미지, 상세 설명)
어떤 것을 다음 ViewController
에 전달해야할지 알았으니 어떻게 하는지 알아볼까요?
prepare(for:sender:)
메서드 활용UIViewController
의 prepare(for:sender:)
메서드를 활용하면 다음 화면으로 정보를 넘겨줄 수 있습니다. 아래 이미지처럼 재정의되지 않은 perpare(for:sender:)
메서드는 아무 것도 하지 않습니다.
하지만 재정의하여 사용하면 전환될 화면인 다음 ViewController
에 데이터를 넘겨줄 수 있죠. 코드를 보시겠습니다.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let indexPath = tableView.indexPath(for: sender as! UITableViewCell) else {
os_log(.fault, log: .ui, OSLogMessage.indexPathIsNil)
return
}
if segue.identifier == Identifier.Segue.artworkDetail {
let followingViewController = segue.destination as? ArtworkDetailViewController
followingViewController?.artwork = artworks[indexPath.row]
}
}
코드를 통해 목표한 요소를 넘겨주고 있음을 확인할 수 있습니다. 상세히 설명하면 아래와 같은 과정을 거치는 것이지요.
1. sender
로부터 선택된 Cell
의 indexPath.row
를 추출
2. artworks
배열의 indexPath.row
번째 인덱스에 있는 요소를 다음 ViewController
의 artwork
프로퍼티로 할당
그럼 데이터를 받는 ViewController
는 전달 받은 데이터를 저장할 프로퍼티를 가지고 있어야 합니다.
final class ArtworkDetailViewController: UIViewController {
// MARK: - Properties
var artwork: Artwork?
(... 후략)
}
Segue
가 실행될 때 데이터를 전달하는 방법아직 제가 재정의한 prepare(for:sender:)
메서드에서 설명되지 않은 부분이 있습니다. 코드를 계속해서 살펴보시죠.
if segue.identifier == Identifier.Segue.artworkDetail {
let followingViewController = segue.destination as? ArtworkDetailViewController
followingViewController?.artwork = artworks[indexPath.row]
}
위 조건문은 segue.identifier
를 검사하여 Identifier.Segue.artworkDetail
인 경우 코드 블럭 안의 내용을 실행한다고 명시하고 있습니다.
Segue
의 identifier
를 설정하는 방법은 먼저 스토리보드에서 Segue
를 만들고, Attributes Inspector
의 Storyboard Segue
섹션의 Identifier
를 작성해주시면 됩니다.
이상으로 UIViewController
의 prepare(for:sender:)
메서드를 재정의하여 화면 전환 간 데이터를 전달하는 방법을 살펴보았습니다.
기능들을 구현하는 과정에서 Segue
를 수행하는 방법에 대해 크게 고민해보지 않았는데, 최근 코드를 통해 Segue
를 실행하는 것을 보고 정리해두어야겠다고 생각했습니다.
보통 스토리보드를 활용해서 Segue
를 수행하는 경우가 많죠. 아래 예시 이미지는 TableView
에서 상세 화면으로 전환할 때 TableView
의 Cell
을 control
키를 누르고 클릭한 후 드래그하여 다음 화면에서 놓는 모습입니다.
이 작업을 수행하면 아래와 같이 화면 전환이 일어난다는 Storyboard Segue
표시를 확인할 수 있습니다.
화면에서 강조된 요소 (예시에서는 TableView Cell
)와 상호작용함으로써 다음 화면인 Artwork Detail View Controller
로 전환됨을 알 수 있습니다.
코드를 활용해 화면 전환을 하는 방법은 Custom Segue
를 만들어서 코드로 작동시키는 방법이 있습니다. 먼저 아래와 같이 View Controller
와 이동할 ViewController
를 연결시켜 줍니다.
이후 만들어준 Storyboard Segue
의 identifier
를 설정합니다.
애플리케이션 사용자의 활동에 따라 Segue
가 일어나야 할 위치에 Segue
가 발생하도록 performSegue(withIdentifier:sender:)
메서드를 작성해줍니다. 예시 상황은 TableView
이므로 tableView(_:didSelectedRowAt:)
메서드에서 실행하도록 하겠습니다.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetail", sender: indexPath.row)
}
1 번 방법의 경우 스토리보드에서 어떤 UI 요소와 상호작용하면 화면의 이동이 일어나는지 확인하기에 편리한 반면 코드 상에서는 확인하기 어렵고, 2 번 방법은 반대로 스토리보드에서 어떤 UI 요소와 상호작용하면 화면의 이동이 일어나는지 확인하기 어려운 반면 코드 상에서 확인하기 좋겠네요. 하지만 저는 시각적으로 잘 나타낼 수 있는 1 번 방법을 선호합니다!
이상 스토리보드와 코드를 활용한 Segue
의 실행 방법을 알아보았습니다.