반응형

서울 가을의 하이라이트는 뭐니 뭐니 해도 한강 불꽃 축제죠! 🎆 매년 10월이면 하늘을 수놓는 불꽃과 수많은 사람들로 한강이 정말 뜨겁게 달아오르는데요. 하지만 막상 가보면 어디에서 봐야 잘 보일지, 또 교통은 어떻게 이용해야 할지 고민되는 분들 많으실 거예요. 오늘은 제가 직접 다녀온 경험을 바탕으로 한강 불꽃 축제 명당과 교통 꿀팁을 소개해드릴게요.


🌉 가장 인기 있는 한강 불꽃 명당: 여의도 한강공원

역시 정석은 여의도 한강공원이에요. 불꽃이 터지는 중심 무대라 가장 웅장한 장면을 바로 앞에서 볼 수 있죠. 다만, 그만큼 사람이 어마어마하게 몰리기 때문에 일찍 가는 게 필수예요. 저는 작년에 오후 2시에 가서 자리 깔고 앉았는데, 이미 좋은 자리는 꽉 차 있더라고요. 🎇
👉 팁: 돗자리 챙기고, 미리 먹을 음식이나 간식 준비해 가면 훨씬 즐겁게 기다릴 수 있어요.


🌳 여유롭게 즐기는 명당: 이촌 한강공원

사람이 너무 많은 게 부담스럽다면 이촌 한강공원을 추천해요. 여의도보다는 조금 거리가 있지만, 불꽃이 시야를 가리지 않고 시원하게 터지는 장면을 볼 수 있어요. 특히 강변 잔디밭에 앉아서 편안하게 즐기기 좋아요. 커플이나 가족 단위 방문객에게 강력 추천하는 명당입니다.


🏙️ 로맨틱한 뷰를 원한다면: 한강대교 & 노들섬

색다른 분위기를 원한다면 한강대교 위에서 바라보는 불꽃도 매력적이에요. 강 위에서 터지는 불꽃과 서울 도심의 야경이 함께 어우러져 로맨틱 그 자체랍니다. 또, 요즘 핫플인 노들섬은 감성적인 분위기와 함께 불꽃을 즐기기 좋아서 인스타 감성샷 찍기에도 딱이에요.


🚇 교통 꿀팁: 지하철이 정답!

불꽃 축제 날은 도로가 거의 주차장이 되기 때문에 교통은 무조건 대중교통을 추천해요. 특히 지하철 5호선 여의나루역, 9호선 국회의사당역이 가장 가까워요. 다만 행사 시간 전후로는 인파가 몰려 역이 통제되는 경우가 있으니, 한두 정거장 전에 내려서 걸어가는 게 현명한 방법이에요. 👟
👉 귀가할 때는 여유 있게 불꽃이 끝나기 전, 조금 일찍 빠져나오는 것도 좋은 전략이에요.


🍔 불꽃과 함께 즐기는 먹거리

명당만큼 중요한 게 바로 먹거리! 근처 편의점이나 푸드트럭에서 간단히 사 먹을 수도 있지만, 줄이 길고 재고가 빨리 동나기 때문에 미리 준비해 가는 걸 추천해요. 피크닉 느낌으로 치킨이나 김밥 싸 가면 불꽃과 함께 더 맛있게 즐길 수 있답니다.


🎇 마무리

올해도 기다려지는 한강 불꽃 축제! 명당을 미리 알고, 교통까지 똑똑하게 준비한다면 복잡한 분위기 속에서도 멋진 추억을 만들 수 있어요. 저는 올해는 이촌 한강공원에서 여유롭게 즐겨보려고 해요. 여러분도 이번 불꽃놀이 꼭 멋지게 즐기시길 바랄게요 ✨

 

반응형

'취미생활' 카테고리의 다른 글

릴로와 스티치 영화 관람 간단후기!  (1) 2025.05.27
반응형

 

 

미션임파서블 파이널 레코닝와 북미에서 같은 날 개봉했는데,

톰형을 제껴버리고 북미 박스오피스 1위를 며칠째 지키고 있는 "릴로& 스티치"

실제로 보고온 후기를 간단히 얘기해보죠! 

 

🎬 줄거리 간단하게 (스포 거의 없음!)

이야기는 우주에서 시작하는데,  외계 생명체 과학자가 만든 ‘실험체 626’,

즉 우리가 아는 스티치는 세상에서 가장 파괴적인 존재로 태어나요.

그런데 우주 감옥에서 탈출해서... 하와이 지구에 불시착!

그리고 그곳에서 릴로, 작은 소녀를 만나면서 이야기가 본격적으로 시작하죠.

이번 영화는 2002년에 나온 원작 애니메이션의 이야기를 그대로 따라가네요. 

 

영화의 진짜 매력 포인트

1. 스티치가 너무 귀엽고 웃겨요! 

처음엔 약간 괴물처럼 생긴 외계인인데, 보면 볼수록 정들어요ㅋㅋ 엉뚱한 행동과 고장난 듯한 말투가 중독성 있어요.

장난꾸러기인데 가끔씩 너무 순수한 모습 보여서 마음이 몽글몽글해져요.

애니메이션에서 느낄 수 있던 그 귀여운 모습을 CG로도 매우 잘 표현해줘서 원작팬들이라면 누구나 좋아할꺼예요.

 

2. 릴로의 현실적인 감정

릴로는 전형적인 '디즈니 공주' 같은 캐릭터가 아니에요.

좀 삐뚤고, 외롭고, 자기만의 세계가 강한 아이. 그래서 더 현실적으로 다가오고, 더 마음이 가요.

어린아이지만 감정 표현이 너무 진짜예요. 이게 어릴 땐 몰랐는데, 어른이 돼서 보니까 울컥하게 하더라구요…

 

3. "오하나"라는 메시지

릴로와 스티치의 관계를 관통하는 말이 바로 “오하나(ʻOhana)”, 하와이어로 ‘가족’을 뜻하는데.

“오하나는 가족이야. 가족은 버리지 않아. 잊지도 않아.”

 

이 대사가 영화의 모든 걸 요약해요.

가족이라는 주제를 이렇게 따뜻하고 담백하게 표현한 영화, 흔치 않아요.

특히 가족과 멀어진 기분이 들 때 이 영화 보면, 괜히 가슴이 꽉 찬 느낌이 들어요🥹

 

 

✅ 총평 – 이건 어린이 영화 그 이상

👧 어릴 때 봤다면 귀엽고 웃기다고 생각했을 영화.
🧑 어른이 돼서 보면 마음을 건드리는 진짜 가족 이야기.

 

스티치가 디즈니 캐릭터들중에는 매우 독특한 개성을 가진 캐릭터라, 매니악한 팬덤이 있는데

사실 국내에는 그런 편이 아닌 것같아요. 그래서 국내흥행은 크게 잘되는 느낌이 아니죠.

원작이 나온 2002년 그쯤은 사실 디즈니 애니메이션의 황금기가 끝난 시점에 나온 작품이고

2000년 일본 문화 개방이후 일본 극장 애니메이션이 크게 선보이던 시기라서

국내에서 스티치 인기는 많이 약한 듯 보이네요.

하지만 이 영화를 통해서 스티치의 매력을 제대로 느껴보기를 추천합니다!

 

반응형
반응형

Swift Concurrency 마스터하기 - 실무 확장을 위한 구조화 전략 3가지

이번 편에서는 지난편에 했던 북마크/스크랩 기능이 포함된 앱 UI를 이어가보죠.

목표는 다음과 같습니다:

  • 비동기 리스트 로딩북마크 토글을 동시에 안정적으로 처리
  • 상태 꼬임 없이 스크롤 중 추가 로딩, 북마크 상태 반영
  • 성공/에러 상태, 이전 데이터 유지까지 고려한 설계

🎯 실무 확장을 위한 구조화 전략 3가지

이번 편에서는 아래 3가지를 집중적으로 소개해요:

  1. 컴포넌트화: UI/로직을 재사용 가능한 단위로 분리하기
  2. 상태 관리 추상화: 공통 비동기 흐름을 하나의 타입으로 묶기
  3. 멀티탭 구조 대응: 북마크 상태를 여러 화면에서 일관되게 유지하기

1️⃣ 컴포넌트화: 북마크 버튼을 독립적인 재사용 단위로 만들기

북마크 토글 기능이 여러 리스트나 상세 화면에서 반복될 때, 동일한 로직을 계속 복붙하게 되면 유지보수가 어려워져요. 그래서 이를 독립적인 뷰 컴포넌트 + 전용 로직으로 분리해봅니다.

📦 BookmarkButtonView

struct BookmarkButtonView: View {
    @Binding var isBookmarked: Bool
    let toggleAction: () async -> Void

    var body: some View {
        Button(action: {
            Task { await toggleAction() }
        }) {
            Image(systemName: isBookmarked ? "bookmark.fill" : "bookmark")
                .foregroundColor(isBookmarked ? .blue : .gray)
        }
    }
}

✅ 사용 예시

BookmarkButtonView(
    isBookmarked: $article.isBookmarked,
    toggleAction: {
        await viewModel.toggleBookmark(for: article.id)
    }
)

이렇게 하면 북마크 UI를 리스트/상세/추천뷰 등 어디에서든 일관되게 사용할 수 있어요. 또한 UI 테스트에서도 이 버튼만 독립적으로 검증 가능해집니다.


2️⃣ 상태 관리 추상화: 공통 비동기 상태를 하나의 모델로 만들기

북마크, 좋아요, 팔로우 등 여러 곳에 등장하는 비동기 토글 패턴은 대부분 다음 흐름을 공유합니다:

  1. 현재 상태 표시
  2. 토글 시 optimistic update
  3. 실패 시 복구

이 흐름을 반복해서 작성하지 않고, Generic 비동기 상태 관리 모델로 추상화할 수 있어요.

🧩 AsyncToggle<T> 구조체

struct AsyncToggle<T: Equatable>: Equatable {
    var value: T
    var isProcessing: Bool = false
    var error: Error? = nil

    mutating func toggle(with newValue: T) {
        value = newValue
        isProcessing = true
        error = nil
    }

    mutating func complete(success newValue: T) {
        value = newValue
        isProcessing = false
        error = nil
    }

    mutating func fail(originalValue: T, error: Error) {
        value = originalValue
        isProcessing = false
        self.error = error
    }
}

이걸 활용하면 북마크 뿐만 아니라 좋아요, 팔로우 등 다양한 상태를 안정적으로 관리할 수 있어요.

ViewModel 예시:

@Published var bookmark = AsyncToggle<Bool>(value: false)

func toggleBookmark() async {
    let original = bookmark.value
    bookmark.toggle(with: !original)
    do {
        try await BookmarkAPI.toggle(id: articleId)
        bookmark.complete(success: !original)
    } catch {
        bookmark.fail(originalValue: original, error: error)
    }
}

3️⃣ 멀티탭 구조 대응: 앱 전역 상태 공유하기

앱이 여러 탭으로 나뉘고, 북마크 상태가 전역에서 공유되어야 할 때는 ViewModel만으로는 부족해요. 이럴 땐 전역 상태 컨테이너를 정의해서 전체 앱이 같은 데이터를 바라보도록 해야 합니다.

🌐 AppState 예시

@MainActor
final class AppState: ObservableObject {
    @Published var bookmarks: Set<Int> = []

    func isBookmarked(id: Int) -> Bool {
        bookmarks.contains(id)
    }

    func toggleBookmark(id: Int) async {
        if bookmarks.contains(id) {
            bookmarks.remove(id)
        } else {
            bookmarks.insert(id)
        }
        try? await BookmarkAPI.toggle(id: id)
    }
}

SceneDelegate, AppDelegate, 또는 SwiftUI App에서 DI:

@main
struct MyApp: App {
    @StateObject var appState = AppState()

    var body: some Scene {
        WindowGroup {
            TabView {
                HomeView()
                BookmarksView()
            }
            .environmentObject(appState)
        }
    }
}

이제 어떤 탭에서 북마크를 추가/삭제해도 다른 탭에서 즉시 반영됩니다. 이건 유저 입장에서 굉장히 자연스러운 UX를 만들어줘요.


❓ FAQ: 실무 확장 구조 관련 자주 묻는 질문들

Q. 북마크 상태를 @Binding으로 넘기면 항상 안전한가요?

A. 값이 바뀌는 순서를 잘 통제하고 있다면 대부분 안전하지만, 복수의 비동기 토글이 동시에 일어나는 경우 충돌이 날 수 있어요. 이럴 땐 Binding보다는 전역 상태 공유 모델이 더 안전합니다.

Q. 북마크 상태가 바뀌었을 때, 리스트에 어떻게 반영되나요?

A. 리스트가 해당 데이터를 참조하고 있다면 @Published 변화로 인해 자동 반영됩니다. 단, 리스트의 참조가 끊겼다면 수동으로 업데이트 해줘야 할 수도 있어요.

Q. 전역 상태를 쓰면 모든 뷰가 무겁지 않나요?

A. @EnvironmentObject는 내부적으로 diffing을 통해 필요한 뷰만 업데이트합니다. 단, 너무 많은 상태를 하나의 전역 객체에 넣으면 유지보수가 어려워지니 feature 단위로 나누는 것이 좋습니다.

Q. 전역 상태에서도 Task.cancel() 같은 처리는 가능할까요?

A. 가능합니다. 상태 객체 내에서 Task를 저장하고, 필요 시 취소하도록 설계할 수 있어요. 다만 이를 관리하려면 구조를 좀 더 정교하게 만들어야 합니다.


✅ 요약: 실무 확장을 위한 3단 전략

전략 목적 핵심 이점
컴포넌트화 UI 단위 재사용 유지보수 쉬움, 테스트 가능
상태 추상화 비동기 토글 통일 로직 중복 제거, 일관성 확보
전역 상태화 멀티 탭 대응 전체 뷰 간 데이터 공유

💬 마무리하며

이번 편은 마치 번외편이지만, 실제로 앱을 만들 때 가장 필요한 고급 구조화 전략들이었습니다.

  • 북마크/스크랩 같은 단일 기능도 여러 뷰/상태에서 엮이면 복잡해지기 쉬움
  • 그럴수록 "분리"와 "공통화"가 해답이 됨

다음 편에서는 이 구조를 테스트 가능한 형태로 감싸서, 의존성 주입 + 단위 테스트로 이어가는 것도 좋겠어요.

혹시 지금까지 구조 중에서 더 다듬고 싶은 부분이 있거나, 적용하고 싶은 다른 기능이 있다면 말해줘. 함께 정리해보자! 💡

 

 

이전글:

[프로그래밍] - Swift Concurrency, 북마크/스크랩 기능이 있는 복합 UI 아키텍처 설계 Part.1

반응형

+ Recent posts