iOS Message(1/3) - UIAlertController

iOS Message

모바일 앱 서비스의 가장 중요한것은 개발자와 사용자 사이의 커뮤니케이션 입니다. 가령 예를 들면 앱의 서버 점검 때문에 일시적으로 사용이 제한될때나, 네트워크가 연결되지 않은 상태를 사용자에게 인지 시키고 한동안 접속하지 않은 사용자에게 초대 메시지를 보내는 등의 경우 메시지를 명시적으로 전달하는 경우가 많습니다.

대표적인 경우로 앱 내에서 사용자에게 메시지를 전달하는 방법으로는 3가지가 있습니다.

  • 메시지창(알림창)

  • 로컬 알림

  • 서버 알림(푸시 알림)

기존의 메시지창의 경우 사용자가 앱을 실행 중 일때만 알림이 가기 때문에 그 외에 사용자가 앱을 사용하지 않을 경우에도 즉각적으로 메시지를 전달해야할 필요가 있을 경우가 종종 발생합니다. 이를 보완하기 위해 고안된 것이 로컬알림서버알림 기능입니다.

로컬 알림과 서버 알림

로컬 알림과 서버 알림은 푸시 메시지 기능입니다. 공식 적인 용어로 이들을 로컬 노티피케이션 , 푸시 노티피케이션 이라고 하고 로컬 푸시, 서버 푸시라고 실무에선 종종 부릅니다.

image: ../Art/remote_notif_multiple.jpg

기본적으로 모바일 디바이스 내에서 로컬 푸시와 서버 푸시를 구현하는 메커니즘은 거의 동일합니다. 하지만 메시지의 출처는 전혀 다릅니다. 로컬 푸시가 앱 내부에서 특정 프로세스에 의해 등록된 메시지를 iOS가 전달하는 방식이라면 서버 푸시는 별도의 서버를 통해 APNs(Apple Push Notification service)라는 애플 고유의 메시징 시스템에게 보낸 메시지가 네트워크를 통해 전달되는 방식이다.

메시지 알림창 - UIAlertController

iOS에서 메시지 창을 구현하는 객체는 UIAlertController 입니다. 뷰 컨트롤러의 일종으로 iOS8.0 이후부터 새롭게 등항한 컨트롤러 입니다. 두기지 기능을 제공하는데 하나는 알림창, 다른 하나는 액션 시트 입니다.

우선 알림창과 액션시트 창의 결정적인 차이는 모달 여부입니다. 알림창은 Modal(모달) 방식으로 화면애 표시되는 반면에 액션 시트 창은 그렇지 않습니다. 모달이란 창이 닫힐 때까지 그 창을 제외한 화면의 다른 부분은 반응할 수 없도록 잠기는 것을 말합니다. 알림창이 표시되는 동안 사용자가 터치할 수 있는 곳은 오로지 알림창의 선택 버튼뿐입니다. 즉 사용자가 알림창에 표시된 선택 버튼 중 어느 하나를 선택하기 전에는 다른 어떤 기능도 이용할 수 없다는 뜻 입니다.(알림처리를 강제한다.)

참고) 알림창이 표시되는 동안 코드는 걔속 실행이 됩니다.

알림창이 화면에 표시되고 있는 동안 앱의 다른 기능을 사용할 수 없는 범위는 사용자의 터치 또는 드래그와 같은 이벤트로 제한됩니다. 애플리케이션 자체적으로 실행하는 내용이 있다면 이는 알림창이 표시 되고 있더라도 계속 실행된다는 뜻입니다. 즉 , 알림창이 애플리케이션의 실행 자체를 멈추는 것은 아니므로 주의해야합니다.

UIAlertController 구현
var alert: UIAlertController = UIAlertController()

    var cancel: UIAlertAction = UIAlertAction()



   override func viewDidLoad() {

        super.viewDidLoad()

        // 1. UIAlertController 생성 -> .alert

        alert = UIAlertController(title: "알림", message: "UIAlertController 샘플 알림창입니다.", preferredStyle: UIAlertController.Style.alert)

        // 2. 버튼을 클릭했을 때 실행할 구문을 작성

        cancel = UIAlertAction(title: "취소", style: UIAlertAction.Style.cancel)

        // 3. UIAlertAction 클래스를 사용하여 생성한 인스턴스를 UIAlertController 인스턴스에 등록하는 과정

        alert.addAction(cancel)

        // 4. 화면에 출력

        self.present(alert, animated:  false)

    }

마지막 UIAlertController는 스토리보드에서 다룰 수는 없지만 하나의 뷰 컨트롤러이기 때문에, 실행 역시 뷰 컨트롤러에 의한 화면 이동 방식을 사용해야합니다.

참고) 취소 버튼이 클릭되면 창은 자동으로 닫히기 때문에* dismiss(animated:) *메소드를 구현해 줄 필요는 없습니다.

TextField가 있는 메시지 창
    @IBAction func tapLoginButton(_ sender: UIButton) {
        let title = "iTunes Store에 로그인"
        let message = "사용자의 Apple ID gaki@naver.com 의 암호를 입력하십시오"
        
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let cancel = UIAlertAction(title: "취소", style: .cancel, handler: nil)
        let ok = UIAlertAction(title: "확인", style: .default, handler: nil)
        alert.addAction(cancel)
        alert.addAction(ok)

        alert.addTextField { (tf) in
            // 플레이스 홀더 설정
            tf.placeholder = "암호"
            // 비밀 번호 표기
            tf.isSecureTextEntry = true
        }
        
        self.present(alert, animated: false)
    }

image

UIAlertAction 으로 추후 처리

위의예제 에서 확인 또는 취소를 눌렀을때 completionHandler를 통해 클로저형태로 액션을 감지하여 추후 동작을 지정할 수 있습니다.

 let ok = UIAlertAction(title: "확인", style: .default) { (_) in
            if let tf = alert.textFields?[0] {
                print("입력된 값은 \(tf.text!) 입니다.")
            } else {
                print("입력된 값이 없습니다.")
            }
        }

위와 같이 ok Action이 클릭이 되었을 경우 입력된 암호 정보를 텍스트필드에서 받아와 그 다음 동작을 진행할 수 있습니다. 그리고 위에허 alert.textFields?[0]로 0번째 배열에 접근을 하였는데 이는 alert Controller에 포함 되어있는 첫번째 텍스트필드를 의미 합니다. 아래와 같이 로그인 기능을 모방하여 만들어 보겠습니다.

 alert.addTextField { (idTf) in
            idTf.placeholder = "아이디"
            idTf.isSecureTextEntry = false
        }

 alert.addTextField { (pwTf) in
            // 플레이스 홀더 설정
            pwTf.placeholder = "암호"
            // 비밀 번호 표기
            pwTf.isSecureTextEntry = true
        }

아이디를 입력 받을 수 있는 텍스트필드를 하나 더 추가하고 확인 버튼을 눌렀을 때는 아래와 같이 입력된 두 텍스트 필드의 정보를 가져 올 수 있습니다.

let ok = UIAlertAction(title: "확인", style: .default) { (_) in
            let loginId = alert.textFields?[0].text
            let loginPw = alert.textFields?[1].text
            
            // 처리...
        }

Reference

![image](https://user-images.githubusercontent.com/33486820/55335165-9967e180-54d5-11e9-94d6-eae6d7e838ea.png



© 2020. by Gaki

Powered by gaki