강의

멘토링

커뮤니티

Cộng đồng Hỏi & Đáp của Inflearn

Hình ảnh hồ sơ của icopy
icopy

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

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 에러 발생

Viết

·

33

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))
    }
iosswiftswiftui

Câu trả lời 1

0

dumveloper님의 프로필 이미지
dumveloper
Người chia sẻ kiến thức


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

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

Hình ảnh hồ sơ của icopy
icopy

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

Đặt câu hỏi