안녕하세요. 후르륵짭짭입니다.
2019년에 SwiftUI가 처음으로 공개 되었는데, 2022년 3년이 지나서 찍먹 중 찍을 한번 해봤습니다. (쫌 많이 늦은 느낌이 들지만 ㅠ ㅠ)
2020년 6월에 IOS 개발을 처음 접했는데, 그 때 감정으로 다시 접하게 됐습니다.
https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
< 해당 사이트에서 Landmark라는 프로젝트 이름으로 튜툐리얼을 진행 할 수 있습니다. >
애플의 Tutorial을 보면서 SwiftUI 프로젝트를 진행하고 제가 다시 저만의 스타일로 다시 만들어봤습니다.
** 종합적인 느낌 **
일단 굉장히 UIKit과 다른 느낌이였습니다.
UIKit은 규칙이 정해진 문서에 글을 적어가는 느낌이였는데, SwiftUI는 블록을 쌓는 느낌이 들었습니다.
- 개발 환경 -
일단 Build를 할 필요없이 Preview로 UI를 개발할 수 있기 때문에 개발 속도가 많이 빨라진 느낌이 듭니다.
사내 프로젝트는 Build 시간이 오래 걸려서 단위테스트를 만들어서 검증하는게 더 빠르기도 하니깐요
하지만,,, 노트북이 좋아야 할 것 같습니다.
이렇게 작은 프로젝트 돌리는데도 Intel 맥북 옛날 제품이면 많이 힘들어 합니다.
- UI -
개인적인 느낌이지만 View를 만드는데 훨씬 적은 시간이 들었습니다.
UIKit을 처음 배울 때, 혼자서 저렇게 만들려면 일주일은 공부해야지 가능했을 겁니다.
그런데 SwiftUI는 더 짧은 시간안에 학습이 가능했습니다.
하지만 아직 배움이 짧아서 부족해서 그렇지만 세세한 View를 그리는데, UIKit 보다 어렵다는 느낌이 들었습니다.
SwiftUI는 자동으로 View의 크기를 만들어주는데,
세세한 것을 배치 줄 때는 AutoLayout이 한번 익히면 더욱 쉽다는 생각이 들었습니다.
- 기능 -
일단 UI를 그려주는 것에서 확실히 다릅니다.
UIKit은 View의 생명주기가 있어 해당 생명주기에 맞춰 View를 그려주게 됩니다.
그리고 만약 View를 다시 그려주고 싶다면 layout를 직접 변경하고 변경 되었다고 알려줘야합니다.
반면 SwiftUI는 React 처럼 지정한 값이 변경이 되면 View를 다시 그려주는 형태로 되어 있습니다. ( 그래서 적응하기 쉽지 않았습니다..)
- 설계 -
UIKit은 주로 MVC 아니면 MVVM으로 개발을 해왔습니다.
특히 사내에서는 MVVM을 사용하는데, 그때 View - ViewModel - Usecase - Repository - Service 이렇게 세세하게 분리하고
ViewModel에서 상태값을 관리하고 View를 다시 그려주는 식으로 사용했습니다.
SwiftUI도 비즈니스 로직과 View를 분리하기하는 것을 장려하기 때문에 MVVM 디자인 패턴을 적용해서 작업했습니다.
실제로 View에서는 일반적인 비즈니스 로직을 넣을 수 없기 때문에같은 비즈니스 로직을 담당하는 Object가 필요했습니다.
하지만 계속 개발하면서 SwiftUI에 MVVM이 맞나???? 이런 생각이 들었습니다.
State나 EnviormentObject, 또는 Binding 등 View에서 상태값을 관리하는 기능을 많이 제공하는데
오직 비즈니스 로직에서만 상태값을 관리하는 방식이 올바른 방식인가??? 라는 생각이 들더군요.
이 부분에 대해서는 좀더 깊게 공부해볼 필요가 있을것 같습니다.
** 다양한 Binding **
SwiftUI에서는 다양한 Binding기능을 제공하는데, 지금 간략하게 정리해보겠습니다.
- State -
State는 View에서 상태관리를 하는 대표적인 바인딩 입니다.
isCircle값이 변경 될 때 View를 다시 그려주게 됩니다.
- Binding -
Binding은 PropertyWrapper의 값을 받아 값을 변경 해주는 바인딩 입니다.
- 초기화
@Binding private var landMark : Landmark
init(landMark : Binding<Landmark>){
self._landMark = landMark
}
Binding을 초기화 할때는 self._바인딩이름 을 넣어 줘야합니다.
바인딩을 사용하는 두가지 방법이 있습니다.
- 값을 변경할 필요 없을 때
LikeView(likeNum: .constant(1))
이렇게 Binding을 그냥 일반 상수로 사용할 때 값을 넘겨줘야 한다면 다음 처럼 넘겨주면 됩니다.
근데 저렇게 사용하려고 Binding을 사용하는 건 아닙니다 절대로 ㅋㅋㅋㅋ
- 값이 변경 된 것을 모두 공유하고 싶을 때
1.
@ObservedObject private var viewModel : LandMarkViewModel
LandmarkDetail(landMark: $viewModel.originData[content.id - 1001])
2.
@State private var isPresented = false
ColorChangeView(state: $isPresented)
이렇게 상위 뷰에서 하위뷰로 ProperyWrapper로 감싸져 있는 값을 Binding에게 전달하면
값이 변경 되는 동시에 View를 다시 그려줄 수 있게 됩니다.
그때 " $ "을 붙여줘서 보내줘야합니다.
- ObservableObject -
ObservableObject는 이 객체는 바인딩 기능을 가진 객체라는 것을 알려줍니다.
ObservableObject는 상태 변화를 알려주는 대표적인 방법 두가지가 있습니다.
- Published 선언
@Published var originData : [Landmark] = []
이렇게 변수에 Published를 선언 해주면 해당 originData가 변경 될 때 마다 상태를 감지하게 되고
이 ObservableObject를 감시하고 있는 View는 View를 다시 그려주게 됩니다.
- objectWillChange.send()
func toggleFavorite(){
filterWithFavorite = !filterWithFavorite
objectWillChange.send()
}
아니면 직접 objectWillChange.send()를 호출해주는 방법도 있습니다.
이렇게 ObservableObject 구성을 마쳤으면 View에 다음과 같이
@ObservedObject private var viewModel : LandMarkViewModel
를 선언 해주면 됩니다.
!!! 주의 !!!
의존성 주입이 아닌 방법으로 @ObservedObject를 선언하면 View를 그려줄 때 마다 객체를 생성하게 됩니다.
@ObservedObject private var viewModel : LandMarkViewModel = LandMarkViewModel()
만약 의존성 주입 방식이 싫다고 한다면 @StateObject를 통해 이 객체는 한번만 생성한다라고 알려주면 됩니다.
@StateObject private var colorHelper = ColorHelper()
자세한 내용은 해당 사이트에 잘 정리 되어 있습니다.
(https://medium.com/hcleedev/swift-observedobject%EC%99%80-stateobject-4f851ed9ef0d)
- EnvironmentObject -
EnvironmentObject는 환경변수로 선언된 객체를 싱클톤과 같은 느낌으로 가져와서 사용할 수 있게 됩니다.
@EnvironmentObject var colorHelper : ColorHelper
따로 init()을 통해서 값을 넘겨 받는 것이 아니라
가장 최상단 또는 해당 변수를 사용하기 상위 View에서 environmentObject 메소드를 통해서 넣어주면 됩니다.
@StateObject private var colorHelper = ColorHelper()
var body: some Scene {
WindowGroup {
MainView(viewModel: LandMarkViewModel())
.environmentObject(colorHelper)
}
}
만약 최상위 뷰에 위와 같이 해줬다면 따로 선언해줄 필요 없이 어디서든지 해당 객체에 접근이 가능해집니다. (싱글톤 느낌으로,,)
SwiftUI에서는 다양한 바인딩 기능을 제공해주고 있습니다.
따라서 MVVM이 맞나라는 생각이 들었습니다.
선언형 View 개발 시스템에서도 MVVM을 사용하는지 아니면 다른 아키텍처를 사용하는지 봐야 할 것 같습니다.
** 참고사이트 **
다양한 Binding 내용정리 :
https://medium.com/hcleedev/swift-observedobject%EC%99%80-stateobject-4f851ed9ef0d
- Binding 초기화 하는 벙법 :
https://stackoverflow.com/questions/57178382/cannot-assign-to-property-text-is-immutable
- Eviorment PropertyWrapper
View를 Present하는 방법 :
https://rhammer.tistory.com/370
EmptyView 생성 방법 :
LazyV(H)Grid :
https://seons-dev.tistory.com/entry/SwiftUI-Grid
NavigationView :
https://seons-dev.tistory.com/entry/NavigationView
- 화살표 방향 지우는 방법
https://stackoverflow.com/questions/58333499/swiftui-navigationlink-hide-arrow
- Navigation바 에서 버튼 생성
https://www.hackingwithswift.com/quick-start/swiftui/how-to-create-a-toolbar-and-add-buttons-to-it
SwiftUI에서 SuperView Layout 잡는 방법 :
https://stackoverflow.com/questions/56508403/how-to-make-width-of-view-equal-to-superview-in-swiftui
https://stackoverflow.com/a/71073866
ScollView Offset:
https://www.fivestars.blog/articles/scrollview-offset/
https://developer.apple.com/forums/thread/650312
GeometryReader :
Dynamic Size 변경하는 방법:
https://daddycoding.com/2020/06/17/swiftui-scaling-animation/
https://www.hackingwithswift.com/quick-start/swiftui/how-to-scale-a-view-up-or-down
Divider 굵기 변경 :
https://stackoverflow.com/questions/58787180/how-to-change-width-of-divider-in-swiftui
ZStack 위치 병경하는 벙법 :
ForEach에서 Index 얻는 방법 :
https://stackoverflow.com/questions/57244713/get-index-in-foreach-in-swiftui
'Xcode > IOS' 카테고리의 다른 글
IOS) Umbrella Framework 생성 및 배포(feat : CoCoaPods) (2) | 2023.01.29 |
---|---|
IOS) TestFlight로 앱 배포하기와 오류들 (feat : X86 제거) (0) | 2023.01.12 |
IOS)XCFramework로 통합 Framework Package를 만들어보자 (2) | 2022.07.17 |
IOS)Moya 간단 사용 정리하기 (0) | 2022.06.26 |
SwiftUI) LazyGride 대한 경험 정리 (0) | 2022.06.11 |
댓글