본문 바로가기

iOS/SwiftUI

SwiftUI) 사용자 이벤트 수집 및 Alert로 확인

사용자 이벤트

사용자 이벤트란?

사용자가 앱을 이용하면서 발생할 수 있는 상황에 대해 정의한 것으로, 앱 개선을 위해 수집할 만한 정보를 선정하여 데이터화 한 것입니다.

크게 화면 전환 이벤트버튼 클릭 이벤트가 있을 수 있습니다.

protocol Event {
    var name: String { get }
    var createdAt: String? { get }
    var metadata: [String: String]? { get }
}

이벤트가 무엇에 대한 것인지 이벤트명(name)과 생성된 날짜(createdAt), 기타 세부사항(metadata)를 수집하였습니다.

예로 홈 화면에서 플레이리스트 화면으로 전환되었다는 것을 다음과 같이 표시할 수 있습니다.

Event(name: "PlaylistViewd",
      createdAt: "2020-12-16T17:15:20.384+0900"
      metadata: ["from" : "home"]
)

메타데이터는 원하는 정보를 여러가지 지정하여 넣을 수 있도록 딕셔너리 형태로 지정하였습니다.

자세한 사항은 깃헙 위키 참고

수집된 이벤트 표시

Alert 생성

Alert는 UIAlertController로 생성할 수 있습니다. 다음과 같이 title과 message 및 스타일을 지정할 수 있습니다.

let alert = UIAlertController(
    title: "\(event.name)",
    message: message,
    preferredStyle: .alert
)

Alert 버튼 추가

Alert가 생성되었을 때 해제할 수 있는 버튼도 추가하였습니다.

alert.addAction(UIAlertAction(
    title: "Dismiss",
    style: .cancel,
    handler: nil
))

AlertEventEngine

수집된 이벤트를 Alert로 화면에 표시하기 위해서는 현재 최상위에 표시된 화면이 무엇인지 알아야 합니다.

window

화면에 떠있는 뷰에서 Alert를 표시하기 위해서는 window를 통해 rootViewController를 알아내야 합니다.

AppDelegateSceneDelegate가 있다면 self.view.window로 필요한 window 정보를 얻을 수 있습니다.

SwiftUI에서는 다른 접근 방식이 필요합니다.

var window: UIWindow? = UIApplication.shared.windows.filter {$0.isKeyWindow}.first

이 방식으로 얻어낼 수 있는데 이를 사용할 때 초기화한 것이 아니고 미리 초기화 해두게 되면 초기화해둔 window가 현재 필요한 window가 아닐 수 있습니다. 따라서 매번 사용할 때마다 다시 초기화할 수 있도록 Computed Property로 지정합니다.

private var window: UIWindow? {
        UIApplication.shared.windows.filter {$0.isKeyWindow}.first
}

그 다음으로 필요한 viewController를 찾아 alert를 띄우면 됩니다. 코드는 다음과 같습니다.

guard let window = window else { return }
var viewController = window.rootViewController

if let presentedViewController = viewController?.presentedViewController {
    viewController = presentedViewController
}

viewController?.present(alert, animated: false, completion: nil)

전체 코드

import UIKit

public final class AlertEventEngine: EventSendable {
    private var window: UIWindow? {
        UIApplication.shared.windows.filter {$0.isKeyWindow}.first
    }

    public func send<T>(_ event: T) where T: Event {
        var message = " "
        if let metadata = event.metadata {
            for (key, value) in metadata {
                message.append("(\(key), \(value))")
            }
        }
        let alert = UIAlertController(
            title: "\(event.name)",
            message: message,
            preferredStyle: .alert
        )

        alert.addAction(UIAlertAction(
            title: "Dismiss",
            style: .cancel,
            handler: nil
        ))

        guard let window = window else { return }
        var viewController = window.rootViewController

        if let presentedViewController = viewController?.presentedViewController {
            viewController = presentedViewController
        }

        viewController?.present(alert, animated: false, completion: nil)
    }
}