티스토리 뷰
UI 살짝 바꾼 것 뿐인데 매번 새로 빌드에서 확인하기 귀찮지 않으신가요? iOS에서 Hot Reloading 기능을 이용해 변경사항을 바로 시뮬레이터에서 확인할 수 있는 라이브러리가 있어 소개해드리려고 합니다. InjectIII라는 라이브러리로 사용법도 엄청 간단해요!
UIKit에서도 SwiftUI에서도 사용 가능합니다.
먼저 UIKit 프로젝트를 기준으로 설명드리겠습니다.
1. 환경변수 설정
먼저 환경번수를 설정해주어야하는데요,
TARGETS > Build Settings > Linking > Other Linker Flags에서 Debug모드에 변수를 추가하고 값 부분에
-Xlinker -interposable
를 입력해줍니다!
2. AppDelegate 설정
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// ✅ 여기부터
#if DEBUG
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle")?.load()
#endif
// ✅ 여기까지
return true
}
//...
AppDelegate > didFinishLaunching 부분에 #if DEBUG ~ #endif 부분을 작성해줍니다.
3. UIViewController Extension 추가
extension UIViewController {
@objc func injected() {
viewDidLoad()
}
}
위 코드를 프로젝트에 추가해줍니다.
4. InjectIII 프로그램 다운
InjectIII를 이용하기 위해선 맥에서 사용하는 추가적인 프로그램이 필요한데요, Mac App Store에서 다운 받으실 수 있습니다!
다운받고 해당 프로그램을 실행시키면 상태창에 아래와 같은 아이콘이 생깁니다.
이 아이콘을 클릭하면 Open project라는 버튼이 맨 위에 있는데요, 이걸 클릭해주시고 사용하고자 하는 프로젝트 디렉토리를 선택해주시면 됩니다. 이때, .xcodeproj 파일이 들어있는 디렉토리를 선택해주세요!
5. 프로젝트 빌드
프로젝트를 빌드해보셨을 때
아이콘이 주황색으로 바뀌고
콘솔에 위와 같은 문구가 뜨면 연결이 완료된 것입니다!
UI값을 바꾸고 저장버튼(cmd+s)를 누를때마다 시뮬레이터가 재빌드 없이 변경되는 것을 확인하실 수 있습니다!
⚠️ 사용하는 데이터 형식 자체가 바뀌거나 하는 경우에는 재빌드가 필요할 수도 있습니다. 변경이 잘 안될땐 한번씩 재빌드를 해주세요!
+SwiftUI에 적용
SwiftUI에 preview 뷰어가 있긴 하지만 많이 불안정하죠.. 또 시뮬레이터에서 바로 보고싶을 때, InjectIII를 적용해볼 수 있을 것 같습니다.
0. 우선 UIKit 방법의 1번(환경변수설정) 4번(프로그램설치)은 동일하게 진행해주세요!
1. 그 다음 새파일을 만들고 아래 코드를 그대로 복붙해 붙여주세요.
#if DEBUG
private var loadInjection: () = {
guard objc_getClass("InjectionClient") == nil else { return }
#if os(macOS) || targetEnvironment(macCatalyst)
let bundleName = "macOSInjection.bundle"
#elseif os(tvOS)
let bundleName = "tvOSInjection.bundle"
#elseif targetEnvironment(simulator)
let bundleName = "iOSInjection.bundle"
#else
let bundleName = "maciOSInjection.bundle"
#endif
Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/"+bundleName)!.load()
}()
import Combine
import SwiftUI
public let injectionObserver = InjectionObserver()
public class InjectionObserver: ObservableObject {
@Published var injectionNumber = 0
var cancellable: AnyCancellable? = nil
let publisher = PassthroughSubject<Void, Never>()
init() {
cancellable = NotificationCenter.default.publisher(for:
Notification.Name("INJECTION_BUNDLE_NOTIFICATION"))
.sink { [weak self] change in
self?.injectionNumber += 1
self?.publisher.send()
}
}
}
extension View {
public func eraseToAnyView() -> some View {
_ = loadInjection
return AnyView(self)
}
public func onInjection(bumpState: @escaping () -> ()) -> some View {
return self
.onReceive(injectionObserver.publisher, perform: bumpState)
.eraseToAnyView()
}
}
#else
extension View {
public func eraseToAnyView() -> some View { return self }
public func onInjection(bumpState: @escaping () -> ()) -> some View {
return self
}
}
#endif
3. 마지막으로 RootView(ContentView로 처음에 생기죠)에 다음과 같이 설정해줍니다.
import SwiftUI
struct ContentsView: View {
// ✅ 추가
#if DEBUG
@ObservedObject var iO = injectionObserver
#endif
var body: some View {
InnerView("Hello, World!")
.eraseToAnyView() // ✅ 추가
}
}
완성입니다!
만약 리로드되는 순간마다 어떤 작업을 하고싶으면
import SwiftUI
struct ContentsView: View {
// ✅ 추가
#if DEBUG
@ObservedObject var iO = injectionObserver
#endif
var body: some View {
InnerView("Hello, World!")
.onInjection { // ✅ 추가
print("reload") // ✅ 원하는 동작
}
}
}
.eraseToAnyView 대신 .onInjection 메서드를 써주시면 됩니다!
⚠️ 오류가 나거나 작동하지 않을 때는 아래와 같은 방법을 시도해보세요!
1. cmd+shift+K(빌드클린)
2. File > Pakages > Reset Pakage Caches
3. Deriven Data 삭제
💬 며칠 사용해보니 SwiftUI에서는 런타임 오류도 많이 나고 생각한 것 만큼 잘 작동하지 않더라구요... 프리뷰만큼이나 불안정하고 자주 재빌드를 해줘야해서 불편합니다. 다만 단일 뷰 환경이 아닌 시뮬레이터에서 앱 전체에서 변경사항을 확인해보기는 좋았어요. 기본 설정만 해두고 필요할때만 써야겠습니다..!
읽어주셔서 감사합니다!
'iOS' 카테고리의 다른 글
[iOS] 메모리릭 찾아내기 (0) | 2024.04.12 |
---|---|
[iOS] Healthkit 사용기 - 아키텍처, 테스터블하게 만들기 (2) | 2023.07.30 |
[iOS] iOS에 GraphQL 적용하기 - Apollo 라이브러리 이용 (0) | 2023.05.31 |
[Swift] DI 라이브러리 소개 및 비교 - Factory, Swinject, Needle, swift-dependencies (1) | 2023.05.26 |
[iOS] 긴 문자열, URL 등의 정적 리소스 관리하기! - .plist, .rtf 이용 (0) | 2023.05.23 |
- Total
- Today
- Yesterday
- 프로그래머스
- Architecture Pattern
- 비동기/동기
- 리액티브 프로그래밍
- SWM
- DocC
- 코디네이터 패턴
- swift
- Flux
- MVI
- Bloking/Non-bloking
- RX
- MVC
- reactive programming
- combine
- ios
- notion
- Swift Concurrency
- 아키텍쳐 패턴
- programmers
- SwiftUI
- GetX
- 노션
- coordinator pattern
- design pattern
- MVVM
- healthkit
- TestCode
- 소프트웨어마에스트로
- Flutter
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |