본문 바로가기

iOS/SwiftUI

SwiftUI) ViewBuilder 와 guard let

일단 결론부터 말하면 ViewBuilderguard let 쓰지 마세요 🌝

AnyView와 Performance

AnyView를 사용하면 퍼포먼스에 영향이 있을 수 있다고 하여 다음의 코드를 ViewBuilder로 변경하고자 하였습니다.

func getDestination(to routingDestination: MiniVibeType, with id: Int?) -> AnyView {
    guard let id = id else{ return AnyView(ErrorView())}
    //TODO: 타입에따라서 다른 destination 보여주게하기! (대부분 id넘겨서 tracklist 보여주기
    switch routingDestination {
    case .magazines:
        return AnyView(MagazineView(magazineID: id))
    case .favorites:
        return AnyView(PlaylistView(playlistID: id))
    case .recommendations:
        return AnyView(PlaylistView(playlistID: id))
    default:
        return AnyView(Text("기본 화면"))
    }
}

ViewBuilder와 메소드

AnyView를 return하는 대신 새로운 뷰 자체를 띄울 수 있도록 다음과 같이 ViewBuilder Property Wrapper로 감싸서 만들었습니다.

struct CategoryRouter {

    @ViewBuilder
    func getDestination(to routingDestination: MiniVibeType, with id: Int?) -> some View {
        guard let id = id else{ ErrorView() }
        //TODO: 타입에따라서 다른 destination 보여주게하기! (대부분 id넘겨서 tracklist 보여주기
        switch routingDestination {
        case .magazines:
            MagazineView(magazineID: id)
        case .favorites:
            PlaylistView(playlistID: id)
        case .recommendations:
            PlaylistView(playlistID: id)
        default:
            Text("기본 화면")
        }
    }
}

그런데 두둥..💥

에러

에러가 발생했습니다.

이것 저것 다해보다 설마 하는 마음에 guard let을 빼고 if let으로 변경해보니 됩니다

@ViewBuilder
func getDestination(to routingDestination: MiniVibeType, with id: Int?) -> some View {
    if let id = id {
        switch routingDestination {
        case .magazines:
            MagazineView(magazineID: id)
        case .favorites:
            PlaylistView(playlistID: id)
        case .recommendations:
            PlaylistView(playlistID: id)
        default:
            Text("기본 화면")
        }
    }
}

왜인지는 역시나 모릅니다.

Memory Leak

메모리 누수

사실 메모리 누수가 발생하여 고치려고 AnyView를 제거해본 것인데 여전히 메모리 누수는 발생하고 아무 소득도 없었습니다.

참고