inflearn logo
강의

Khóa học

Chia sẻ kiến thức

SwiftUI + TCA: Hoàn thiện kiến trúc iOS thế hệ mới qua dự án thực tế

Quản lý trạng thái lựa chọn ảnh trong Reducer

예제 빌드시 The compiler is unable to type-check this expression in reasonable time 에러 발생

66

icopy

21 câu hỏi đã được viết

0

//
//  EditImageReducer.swift
//  AppStore
//
//  Created by Langpeu on 12/24/25.
//

import ComposableArchitecture
import SwiftUI
import SwiftData
import Photos

@Reducer
struct EditImageReducer {
    
    @ObservableState
    struct State {
        var userImage: Image?
        var assets: [PHAsset] = []
        var selectedPhoto: (id: String, data: Data)?
        @Presents var alert: AlertState<Action>?
        
    }
    
    enum Action {
        case onAppear(image: Data?)
        case setUserImageData(Data?)
        case setUserImage(Image)
        case authResult(Bool)
        case onSelectPhoto(id: String, data: Data)
    }
    
    var body: some Reducer<State, Action> {
        Reduce { state, action in
            switch action {
            case let .onAppear(imageData):
                return Effect.run { send in
                    let isAuth = await PhotoManager.requestAuthorization()
                    await send(.authResult(isAuth))
                    await send(.setUserImageData(imageData))
                }
            case let .authResult(isAuth):
                if isAuth {
                    let assets = PhotoManager.getAssets()
                    state.assets = assets
                } else {
                    state.alert = AlertState.creatAlert(type: .error(message: "권한이 없습니다"))
                }
            case let .setUserImageData(data):
                guard let data, let uiImage = UIImage(data: data) else {
                    return .none
                }
                return .send(.setUserImage(Image(uiImage: uiImage)))
                
            case let .setUserImage(image):
                state.userImage = image
                return .none
            case let .onSelectPhoto(id, data):
                state.selectedPhoto = (id: id, data: data)
            }
            return .none
        }
    }
}

struct EditImageView: View {
    @Bindable var store: StoreOf<EditImageReducer>
    let colums: [GridItem] = .init(repeating: .init(.flexible()), count: 3)
    
    @Query private var users: [User]
    private var user: User? {
        users.first
    }
    
    var body: some View {
        ScrollView {
            VStack {
                Text("선택된 이미지")
                // 선택된 이미지
                Group {
                    if let image = store.userImage {
                        image
                            .resizable()
                            .scaledToFit()
                    } else {
                        Color.gray.opacity(0.2)
                    }
                }
                .frame(width: 100, height: 100)
                .clipped()
                .cornerRadius(8)
            }
            
            LazyVGrid(columns: colums, spacing: 10) {
                ForEach(store.assets, id: \.localIdentifier) { asset in
                    let isSelectedImage = store.selectedPhoto.id == asset.localIdentifier
                    AssetImageView(asset: asset, isSelected: isSelectedImage, onTap: { data in
                        //TODO: onTap
                        store.send(.onSelectPhoto(id: asset.localIdentifier, data: data))
                    })
                    .clipped()
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                }
            }
            .padding(8)
        }
        .onAppear() {
            store.send(.onAppear(image: user?.imageData))
        }
    }
    
}

private struct AssetImageView: View {
    let asset: PHAsset
    let isSelected: Bool
    let onTap: (Data) -> Void
    let imageWidth: CGFloat = (UIScreen.currentWidth - 16 - 20) / 3
    
    @State private var uiImage: UIImage? = nil
    var body: some View {
        Group {
            if let uiImage = uiImage {
                Image(uiImage: uiImage)
                    .resizable()
                    .scaledToFill()
                    .onTapGesture {
                        if let data = uiImage.jpegData(compressionQuality: 1.0) {
                            onTap(data)
                        }
                    }
            } else {
                Color.gray.opacity(0.2)
            }
        }
        .frame(width: imageWidth, height: imageWidth)
        .overlay(alignment: .topTrailing, content: {
            if isSelected {
                Image(systemName: "checkmark.circle.fill")
                    .foregroundColor(.green)
                    .frame(width: 20, height: 20)
            }
        })
        .onAppear() {
            PhotoManager.fetchImage(asset: asset) { uiImage in
                self.uiImage = uiImage
            }
        }
    }
}

75번라인

var body: some View 

에서 아래 빌드에러 발생

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
----

위와 같은 에러로 빌드가 안되서
아래 처럼 처리 했습니다.

(Xcode26.2 + M1Pro Macbook)

 

포인트: let isSelectedImage = ... 같은 로컬 let + 복잡한 클로저를 ForEach 내부에서 직접 쓰면 타입체커가 더 힘들어해. 함수로 빼면 거의 항상 해결됨.

 

            LazyVGrid(columns: colums, spacing: 10) {
                ForEach(store.assets, id: \.localIdentifier) { asset in
                    assetCell(asset)
                }
            }
            .padding(8)
        }
        .onAppear() {
            store.send(.onAppear(image: user?.imageData))
        }
    }
    
    @ViewBuilder
    private func assetCell(_ asset: PHAsset) -> some View {
        let isSelectedImage = (store.selectedPhoto?.id == asset.localIdentifier)
        AssetImageView(
            asset: asset,
            isSelected: isSelectedImage,
            onTap: { data in
                store.send(.onSelectPhoto(id: asset.localIdentifier, data: data))
            })
        .clipped()
        .clipShape(RoundedRectangle(cornerRadius: 8))
    }

ios swift swiftui

Câu trả lời 1

0

dumveloper


The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

TCA가 복잡한 제너릭 구조가 많아서 코드가 복잡해지면 타입 추론이 길어지면서
컴파일 에러로 저런 모호한 메시지를 보여주는 경우가 많습니다.
질문자님 처럼 함수분리를 하거나 명시적으로 타입을 넣어줘서 타입추론을 쉽게 해줘야합니다.

강의를 다 듣고난 후

0

25

2

android crud중 c 영상이 12초만 있는 잘린 영상이에요.

0

48

2

수강 기간 연장 문의

0

51

1

수강연장부탁드려도될까요..

0

63

2

Combine Playground 에서 실행 시

0

78

2

70강 - 글로벌 액터로 격리된 Protocol 을 extension 에서 conform 시 타입 본체의 격리 수준 질문

0

67

1

searchable이 화면 하단에 위치해요

0

80

2

Drawing Cycle 관련 질문

0

86

1

앱 제작 시 주로 코드로 작성하시는 이유가 있을까요?

0

112

2

델리게이트 패턴 관련 질문

0

84

2

ios 애드몹 광고

0

165

2

수강 기간 연장 부탁드릴 수 있을까요?

0

89

1

활용 앱 57강 질문입니다.

0

63

1

그래프 그리기 위한 API가 프리미엄 요금제를 구독해야만 가능하다고 합니다...ㅜㅜ

0

90

2

과거 ai없을때 듣고 다시 듣는 중인데

1

67

1

활용 앱 30강 에러 질문입니다

0

80

2

TextField 에 Binding 으로 연결하면 에러 발생

0

67

1

xcode 26.2 에서 ReducerOf<Self> 이슈

0

90

2

20강 Task 내부에서 nonisolated async 호출 예제 질문드립니다

0

96

2

19강 Actor 의 동작 관련해 질문드립니다

0

108

2

기초앱 17강 Contraints 설정 질문입니다.

0

82

2

소리가 ㅠㅠ

0

68

2

해당 강의에서 나오는 노션 링크는 따로 제공안되나요 ?

0

98

2

해당 강의는 추가 오픈하는건가요?

0

111

2