Search

제너릭 커스터마이징과 코드 추상화

분류
기타
SwiftUI
생성 일시
2023/01/15 04:14
최종 편집 일시
2023/07/11 08:19
멘토링 요청시간
2023/01/15 20:00
최종 편집자
멘토링 신청자
이승준
담당멘토
유재호
강사용 질의응답
멘토FAQ(보조강사용)
배정상태
해결완료
번호
14
신청팀
개인
멘토링 완료시간
2023/01/15 21:00
비용지급
지급완료
소요시간
1
작성자
이승준

질문

1.
팀원들과 함께 팀프로젝트를 진행하기 전, 알맞게 추상화된 코드로 적재적소에 코드를 재활용하고 싶어서 제너릭과 프로토콜을 연습 중입니다.
2.
특히 코드 추상화는 코드를 구현하는 사람의 생각을 추상화하는 것이라 그런지.. 제 코드를 추상화하는 데도 쉽지 않았습니다.
3.
여러 시행착오를 겪고 있지만, 아래 레포지토리의 리드미에 적힌 내용대로 연습 중에 있습니다.
4.
제너릭과 프로토콜을 활용해서 어떻게 하면 코드를 더 팀원들이 이해하기 쉽고 재활용하기 좋게 추상화할 수 있을지 조언과 요령을 구하고 싶습니다.
a.
또한 제너릭으로 어디까지 될 지, 어디까지가 불가능한지를 사전에 할 수 있을까요..?
b.
SwiftUI 에서는 ForEach가 제너릭 타입이 해셔블하지 않으면 활용할 수가 없어서 구현을 다 해놓고 다시 갈아 엎어야 했던 문제가 있습니다 ㅠㅠ
5.
감사합니다!

화면캡쳐

struct NavigationModifier<NavigationLinkDestinationView: View>: ViewModifier { let journeyToolbar: JourneyToolbar<NavigationLinkDestinationView> let isRefreshableView: Bool var tabSelection: Binding<Int> func body(content: Content) -> some View { content .toolbar { toolbarBuilder(toolbar: journeyToolbar) } } @ToolbarContentBuilder private func toolbarBuilder(toolbar: JourneyToolbar<NavigationLinkDestinationView>) -> some ToolbarContent { switch isRefreshableView { case false: ToolbarItem(placement: toolbar.toolbarItemPlacement) { NavigationLink(destination: { if let destination = toolbar.destination { destination } }, label: { if let iconName = toolbar.toolbarIconName { Image(systemName: iconName) .foregroundColor(.accentColor) } }) } case true: ToolbarItem(placement: toolbar.toolbarItemPlacement) { Button { tabSelection.wrappedValue = toolbar.selectionTag } label: { if let iconName = toolbar.toolbarIconName { Image(systemName: iconName) } else { Text("MyJourney") .bold() .foregroundColor(.black) } } } } } } struct JourneyToolbar<ContentView: View>: Identifiable { let id: String = UUID().uuidString let toolbarItemPlacement: ToolbarItemPlacement let toolbarIconName: String? let destination: ContentView? var selectionTag: Int }
Swift
복사

프로젝트 주소

위 질문에 해당하는 질문의 링크나 스크린샷을 여기에 추가해 멘토분들이 참고할 수 있도록 하세요.
mydiary-20230110-personal-46
APPSCHOOL1-REPO

멘토링 진행 (2022-01-15 오후 8시 ~ 9시)

제네릭이 일반적으로 타입(어레이, 딕셔너리), 메서드에서 사용되는 경우에 대한 설명
스유에서 커스텀 타입을 만들 때, nested 열거형으로 타입을 지정해두고, 이니셜라이저에서 타입을 고르는 방법 설명
some View 를 내뱉는 연산 프로퍼티, 메서드라고 @ViewBuilder 가 꼭 필요한 게 아님. 습관적으로 붙이지 말자.
우리가 어떤 타입에, 어떤 클로저를 넣어주고 싶을 때 내부에서 @escaping 클로저로 받을 수 있듯이
어떤 타입에, 개발자가 커스터마이징 된 View 를 넣고 싶을 때, @ViewBuilder 를 사용할 수 있다.
HStack, VStack, Button 같은 애들이 애초에 뷰빌더로 만들어진 것임. 개발자가 자유롭게 디자인을 넣을 수 있다는 점을 리마인드해보면 좋다.
협업 하는 다른 동료들을 위해서, 편리한 수정자(modifier)를 만들어주려는 의도는 좋지만
튜닝의 끝은 순정이듯이, 편하게 하는 것과 vs 별도의 코드 복잡성이 생기는 것 사이의 trade-off 를 따져봐야 한다.
이 개념이 확장되면 → 디자인 시스템이 된다. 현업 가면 웬만하면 다 디자인 시스템이 있을 것.
면접 볼 때는, 내가 이렇게 대단한 modifier 를 만들었어요 보다는, 다른 개발자들과 동일한 디자인을 생산해내기 위해, 어떤 고민을 했었고 이런 식으로 디자인시스템을 구현했습니다. 라고 강조하는 방향이 더 어필이 될 듯 하다.
디자인시스템의 끝판왕은, 의도적인 컴파일 에러를 유발하는 것이다. 컴파일이 안 되게 디자인한다면, 실수할 확률이 극도로 줄어드니까.