티스토리 뷰

반응형

안녕하세요 :) Zedd입니다.

제목이 넘나 구구절절한 느낌이 있는데...

정말 말 그대로 Delegate를 이용해서 ViewController간 데이터를 전달해볼거에요.

보통 ViewController간의 데이터전달은 prepare에서 아니면 뭐 IBAction안이라던가..


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "segue name"{

            let PlaySoundVC = segue.destination as! PlaySoundsViewController

            PlaySoundVC.recordedAudioURL = recordedAudioURL

        }

    }

이런식으로 데이터를 전달하는 것을 볼 수 있습니다!!

이게 잘못됐다!!!!!!는 아닌데,

이런식으로 직접적으로 데이터를 전달하게되면, 

두 개의 ViewController의 상관관계가 깊어지고, 한 ViewController에서의 변화가 다른 ViewController에게 영향을 줄 수 있다고 합니다. 

그래서!!! Delegate를 이용해서 데이터를 전달하는 것이 좋다고 해요 :)

암튼 ㄱㄱ


Delegate를 이용한 ViewController간 Data전달방법





위 예제처럼 다른 ViewController에서 한 ViewController로 "데이터"를 보낸거죠?

Delegate를 이용해서 보낸거랍니다. 해봅시다.


프로젝트를 만들어주시고,




이렇게 스토리보드 작업을 해주세요.

첫번째 데이터를 받는 ViewController는 데이터를 받으니까, ReceiveViewContoller라고 해줬고, 

오른쪽의 데이터를 보내는 ViewController는 SendViewController라고 해줬어요.

그리고 +버튼의 segue에는 identifier를 지정해줍니다. 

일단 이렇게 기본적인 setting작업이 끝났어요.



먼저, 프로토콜에 대해서 저번~~에 배웠었죠?

만약 어떤 프로토콜이 있다면, 그 프로토콜을 채택하고, 준수해야합니다.

그리고 대리자 위임도 빼면 안되겠죠.

이 사실을 알고 시작합시다.



자. 프로토콜을 만들어봅시다.

protocol SendDataDelegate {

    func sendData(data: String)

}

프로토콜은 메소드를 정의할 때, 구현은 안하고 정의만 한다고 그랬죠? 우리는 데이터를 보내줄 메소드를 하나 작성합시다.



그리고..데이터를 보내는 ViewController에서, 작업을 해줘야겠죠?

프로토콜타입의 변수를 하나 만듭니다. 


class SendViewController: UIViewController {

    var delegate: SendDataDelegate?

@IBOutlet weak var myTextField: UITextField!

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

    }

    @IBAction func myButtonClicked(_ sender: Any) {

        if let data = myTextField.text {

         delegate?.sendData(data: data)

            dismiss(animated: true, completion: nil)

        }

    }

}

SendViewController의 코드인데요. 하나하나 설명드릴게요.

var delegate: SendDataDelegate?

delegate라는 변수를 하나 만들어줬어요. 그리고 타입은!!!! 타입은 아까 우리가 만들어준 프로토콜의 타입이네요.

위 코드에서 우리가 SendDataDelegate를 채택했나요? 

채택을 안했죠? 그냥 SendDataDelegate타입의 변수를 하나 만들어준 것 뿐입니다.

그러므로 SendViewController는 SendDataDelegate를 준수하지 않아도 됩니다. 채택을 안했으니까!!!!!

즉, SendDataDelegate의 메소드인 sendData()를 구현하지 않아도 됩니다. 그냥 sendData()에 접근할 수 만 있게 됩니다. 

@IBAction func myButtonClicked(_ sender: Any) {

        if let data = myTextField.text {

         delegate?.sendData(data: data)

            dismiss(animated: true, completion: nil)

        }

    }

그리고 이 코드, delegate는  SendDataDelegate의 타입이니, sendData()에 접근이 가능하다고 그랬죠? 우리가 하고 싶은 일은 우리의 TextField에 있는 Text를 일단 보내는 거에요. 그러니까 sendData에 우리의 Text를 파라미터로 넣어서 호출합니다.

SendViewController가 해야할 일은 여기서 끝나게 됩니다.



그럼 데이터를 받는 ReceiveViewContoller쪽에서는 어떻게 해야할지 봅시다.

자. 데이터를 받는다고 그랬죠? 그것도 직접적인 데이터 전달이 아니라!!!!! 

Delegate를 이용해서 데이터를 받을거에요. 우리가 Delegate를 사용할 때를 생각해봅시다.

채택하고, 준수하고 대리자 위임하고, 해당 프로토콜의 메소드를 구현하기만 하면!!! Delegate가 알아서 해줬죠?

ReceiveViewContoller에서도 똑같이 해주면 됩니다.


1. 채택.

class ReceiveViewContoller: UIViewController,SendDataDelegate{

..

}

(원래는  extension으로 해주는게 convention에 맞지만...일단 이렇게 해주겠습니다.)




2. 준수

그러면 늘상 보는..넌 SendDataDelegate를 준수하지 않았구나...라는 에러.

왜냐하면 우리의 sendData()메소드는 optional이 아니므로, 이 프로토콜을 채택한 곳은 반드시 구현해줘야합니다. 

 func sendData(data: String) {

        myLabel.text = data

   }

이렇게요. 

우리가 하고싶은 일은 Data를 어케어케 받는데, 이걸 내 label에 적고 싶은거였죠? 하고싶은대로 구현해줍니다.


3. 대리자 위임

우리..?음..저는 일단 거의 매일 viewDidLoad()에 뭐 tableview.delegate = self이런식으로 했었는데..

이번엔 대리자 위임을 어디서 해주어야 할까요?

바로 위에서 걸어놓은..

여기서...


ReceiveViewContoller에서, +버튼을 누르면, SendViewController가 modal로 떴었죠?

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "show" {

            let viewController : SendViewController = segue.destination as! SendViewController

                viewController.delegate = self

        }

    }

이렇게.

우리가 직접적으로 데이터를 보내는 과정과 거의 유사한데요. 다만 다른점은 저 안에서 해당 ViewController의 IBOutlet에 직접 접근하지않고, 저기서!!!!

그냥 대리자 위임을 해준것뿐이네요. 내가(ReceiveViewContoller) 대리자가 되겠다는 것이죠.


이제 실행하면!! Delegate로 데이터가 잘 전달 되는 것을 볼 수 있습니다. 

오늘 코드는 제 깃헙에 올려놓을 테니, 참고하시길 바랍니다 :) 

(오늘 예제와는 다르게 SendDataDelegate를 extension으로 뺀 코드랍니다.)

Delegate패턴은 iOS에서 정말 중요하다고 할 수 있어요.

Swift자체가 프로토콜 지향 프로그래밍 패러다임을 따르고 있으니까요.

반드시 알아두셔야합니다 XD

도움이 되었길 바래요..!!



반응형
댓글
  • 프로필사진 테일러 와... 진짜 감사합니다 ㅠㅠㅠ 이거때매 며칠 끙끙앓고 있었는데,,, 덕분에 코드 구현했어요!! 감사합니다! 2018.06.16 16:09
  • 프로필사진 막 ios 개발을 시작한 왕초보입니다...! 게시글 정독하며 열심히 공부중이에요 감사합니다! ㅎㅎ 혹시 protocol 선언은 보통 따로 파일을 만들어서 구현해 놓나요? 2018.11.02 09:50
  • 프로필사진 Favicon of https://zeddios.tistory.com BlogIcon Zedd0202 개인 취향이긴 하지만..저는 따로 파일을 만들어서 정의하진 않습니다. 2018.11.02 11:45 신고
  • 프로필사진 prepare 함수를 쓰지 않은 경우는 대리자 위임을 어디에서 해주어야 하나요? 화면 전환 방식을 prepare을 쓰지 않는 방식으로 해서.. 2020.04.27 23:13
  • 프로필사진 Favicon of https://zeddios.tistory.com BlogIcon Zedd0202 viewController 인스턴스만드신 뒤에 그걸 present나 push해주실텐데, viewController만드시고 나서 viewController.delegate = self 해주시면 됩니다. 2020.04.28 10:52 신고
  • 프로필사진 감사합니다! 2020.04.29 16:35
  • 프로필사진 그럼 전전뷰로 delegate 프로토콜을 통한 값전달을 할때에는 대리자 위임을 할 방법은 없을까요? 정말 많이 시도해봤는데 안되네요ㅜㅜㅜㅜ 2020.04.29 20:17
  • 프로필사진 Favicon of https://ggasoon2.tistory.com BlogIcon ggasoon2 dismiss 데이터 전달 해결했습니다!! 감사합니당~ 2021.01.18 23:33 신고
댓글쓰기 폼
반응형
Total
3,525,890
Today
3,132
Yesterday
3,543