actionSheet

 

ActionSheet 를 사용하는데 deprecated 되었다고 confirmationDialog를 사용하라고 합니다. 바로 알아봅시다.

 

ConfirmationDialog

가장 기본적인 confirmationDialog 입니다. 첫번째 인자로 titleKey가 들어가고 isPresented 에 바인딩값을 연결해준 뒤 action 클로저 안에 우리가 평소에 쓰는 Button을 쭉 나열하면 됩니다.

 

struct ContentView: View {
    @State var isPresented = false
    
    var body: some View {
        Button(action: {
            isPresented = true
        }) {
            Text("사진 불러오기")
                .padding()
        }
        .confirmationDialog(
            "제목",
            isPresented: $isPresented,
            actions: {
                Button("카메라") {
                    print("카메라 선택")
                }
                Button("라이브러리") {
                    print("라이브러리 선택")
                }
            }
        )
    }
}

기본적으로 Cancel 버튼이 존재하고 제목이나 메세지가 생략이 가능합니다.

 

메세지 추가

.confirmationDialog(
            "제목",
            isPresented: $isPresented,
            actions: {
                Button("카메라") {
                    print("카메라 선택")
                }
                Button("라이브러리") {
                    print("라이브러리 선택")
                }
            },
            message: {
                Text("불러올 사진 위치를 선택해주세요.")
            }
        )

제목 추가

세번쨰 인자로 존재하는 titleVisibility 를 통하여 설정 가능합니다.

.confirmationDialog(
    "제목",
    isPresented: $isPresented,
    titleVisibility: .visible,
    actions: {
        Button("카메라") {
            print("카메라 선택")
        }
        Button("라이브러리") {
            print("라이브러리 선택")
        }
    },
    message: {
        Text("불러올 사진 위치를 선택해주세요.")
    }
)

ActionSheet.Button의 .destructive

.destructive 의 설정은 Button을 생성할 때 할 수 있습니다.

Button("카메라", role: .destructive) {
    print("카메라 선택")
}

 

확실히 기존의 ActionSheet 보다 더욱 더 선언형에 맞게 변화된 모습이 보이네요. 사용하기에도 더욱 편한것 같습니다.

반응형

SwiftUI의 Preview는 따로 앱을 빌드하여 시뮬레이터를 실행하지 않고도 코드를 입력하면 바로바로 눈에 보이도록 해주는데요. 이로 인해 더욱 더 생산성 높은 작업을 할 수 있도록 도와줍니다. SwiftUI에서 하나의 ViewController 같은 화면이 아닌 하나의 Component View를 만드는 경우가 많습니다. 하지만 이럴 때도 Preview는 선택한 기기의 화면으로 보입니다. 이런 경우나 여러가지의 형태(가로모드, 세로모드) 등등 을 한눈으로 확인 할 수 있도록 해주는 Preview의 기능에 대해 알아봅시다.

 

1. PreviewLayout

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewLayout(.device)
        ContentView()
            .previewLayout(.fixed(width: 400, height: 200))
        ContentView()
            .previewLayout(.sizeThatFits)
    }
}

previewLayout은 말 그대로 preview 화면의 레이아웃에 관련된 함수입니다. 의미도 모두 직관적이라 따로 설명은 생략하도록 할게요!

위 코드 처럼 View 타입을 여러개 선언해주게 되면 아래 이미지처럼 한번에 여러개의 Preview를 볼 수 있습니다. Component View를 작성할 때 .sizeTahtFits을 자주 사용하고 있습니다.

 

 

previewLayout

 

 

2. PreviewDevice, PreviewDisplayName

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewDevice(PreviewDevice(rawValue: "iPhone 12 mini"))
            .previewDisplayName("iPhone 12 mini")
        ContentView()
            .previewDevice(PreviewDevice(rawValue: "iPhone 13 Pro Max"))
            .previewDisplayName("iPhone 13 Pro Max")
    }
}

 먼저 previewDevice는 아이폰 기기의 이름으로 preview의 디바이스를 직접 변경시켜 줄 수 있습니다. Xcode에서 시뮬레이터를 실행할 때 기기를 하나만 선택하여 하나의 기기로 실행하게 되는데 이를 이용하면 해당 화면이 여러 화면에서 어떻게 동작되는지 확인할 수 있습니다. PreviewDevice의 enum을 인자로 받게 되어있는데 해당 기기들이 case로 정해져 있지 않고 저렇게 String값으로 생성해줘야 한다는게 좀 불편하네요... 자주 사용하시는 분들이라면 따로 enum을 정의해도 좋을 것 같네요!

 

 PreviewDisplayName은 Preview에 이름을 붙혀줍니다. 아래 사진을 보면 기기 위에 정의해둔 이름이 붙혀인 것을 보실 수 있습니다.

previewDevice, previewDisplayName

 

 

3. Preview 가로모드로 보는법

아쉽게도 Preview에서는 가로모드가 지원되지 않습니다. 하지만 위에서 사용되었던 previewLayout을 사용하면 됩니다!

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewLayout(.fixed(width: 1180, height: 820))
    }
}

아이패드 가로모드

 

반응형

일반적으로 Assets에 고정된 색상을 등록하고 사용하지만 가끔은 서버에서 받은 hex값을 사용하여 색상을 표현해야 하는 경우가 있다.

역시 일반적인 방법으로 Color를 Extension 하여 새로운 이니셜라이저를 추가해준다.

extension Color {
    init(hex: String) {
        let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int: UInt64 = 0
        Scanner(string: hex).scanHexInt64(&int)
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            (a, r, g, b) = (1, 1, 1, 0)
        }

        self.init(
            .sRGB,
            red: Double(r) / 255,
            green: Double(g) / 255,
            blue:  Double(b) / 255,
            opacity: Double(a) / 255
        )
    }
}

 

출처: https://stackoverflow.com/questions/56874133/use-hex-color-in-swiftui

반응형

iOS 의 키보드를 보면 기본적으로 키보드를 내리는 키가 있지만 많은 이용자들이 화면을 탭했을 때 키보드가 내려가는 동작이 익숙하다. 아주 간단하게 SwiftUI에서 구현하는 방법이 있다.

 

1. Extension 선언

extension UIApplication {
    func addTapGestureRecognizer() {
        guard let window = windows.first else { return }
        let tapGesture = UITapGestureRecognizer(target: window, action: #selector(UIView.endEditing))
        tapGesture.requiresExclusiveTouchType = false
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        window.addGestureRecognizer(tapGesture)
    }
}

extension UIApplication: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true // set to `false` if you don't want to detect tap during other gestures
    }
}​

 

2. 사용

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
        }
    }
}

위와 같이 최상단의 View에 onAppear를 호출하는것으로 모든 화면에서 해당 동작이 적용된다.

 

출처: https://stackoverflow.com/questions/56491386/how-to-hide-keyboard-when-using-swiftui

반응형
extension Bundle {
    var appName: String {
        return infoDictionary?["CFBundleName"] as! String
    }

    var bundleId: String {
        return bundleIdentifier!
    }

    var versionNumber: String {
        return infoDictionary?["CFBundleShortVersionString"] as! String
    }

    var buildNumber: String {
        return infoDictionary?["CFBundleVersion"] as! String
    }
}

사용할 때에는 아래와 같이 사용합니다.

let str = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"

 

출처: https://stackoverflow.com/questions/25965239/how-do-i-get-the-app-version-and-build-number-using-swift

반응형

보통 Git이나 Cocoapods 등 terminal을 켜서 특정 작업을 진행한 뒤 다시 Xcode를 실행하기 위해 Finder를 다시 열거나 Xcode를 실행한다. 만약 Cocoapods을 사용하는 프로젝트인 경우 .xcworkspace 파일을 실행해야 하고 그렇지 않은 경우 .xcodeproj 을 실행하게 된다. 

open MyProjectName.xcodeproj

open MyProjectName.xcworkspace

위 명령어를 입력해 Cocoapods의 사용 유무에 따라 직접 입력해 줄 수도 있다. 하지만 xed 명령어를 사용하면 더욱 더 생각할 필요 없이 바로 실행이 가능하다.

 

Xed 사용

xed .

해당 명령어를 입력하면 만약 xcworkspace 파일이 존재할 경우에는 해당 파일을 우선적으로 실행하고 그렇지 않은 경우 xcodeproj파일을 실행하게 된다. 즉 Cocoapods의 사용 유무를 전혀 고려할 필요도 없다!

 

이제 프로젝트 파일을 다시 열기전에 open ... 이라던지 터미널을 끄고 Xcode 아이콘을 눌러 실행해준다던지 할 필요가 전혀 없다!!

반응형

'ios > Xcode' 카테고리의 다른 글

Xcode 13.2 - Internal error: missingPackageDescriptionModule  (0) 2021.12.18

1. 왜 SwiftUI의 Alert이 아닌 UIKit의 Alert을 사용하는가?

SwiftUI의 Alert

먼저 SwiftUI에서 제공되는 Alert을 사용하기 위한 필요한 요소에 대해 알아보자.

1. alert이 열려있는지 닫혀있는지에 대한 정보를 담은 Bool 타입의 State 변수를 선언한다.

2. View에 alert을 체이닝 형식으로 선언한 후 아까 선언한 State 변수를 연결한다.

3. View의 alert 클로저에 Action처리를 포함한 Alert(View)을 추가한다.

struct AView: View {
	// 1
    @State var isShowingAlert = false
    
	var body: some View {
    	VStack {
        	Button(action: { 
            	isShowingAlert = true
            }) {
            	Text("show alert")
            }
        }
        .alert(isPresented: $viewModel.showingPayAlert) { 	// 2
            // 3
            Alert(
                    title: Text("알림"),
                    message: Text("수락하시겠습니까?"),
                    primaryButton: .default(Text("확인")) {
                        print("action!")
                    },
                    secondaryButton: .cancel(Text("취소")
            )
        }
    }
}

 SwiftUI에서 제공되는 Alert을 사용하려면 해당 Alert이 열림과 닫힘을 알 수있는 State 변수 하나, View타입 끝에 체이닝 형식으로 alert을 하나하나 달아줘야 한다. 만약 여러개의 화면에 모두 각각 alert이 필요하면 매번 State 변수를 만들고 매번 alert을 달아준 다음 해당 action을 추가해야한다. 물론 최상단의 View에 하나의 alert을 달아놓고 매번 최상단의 alert의 binding 변수를 변경해주거나 하는 방법으로 해결할 수 있지만 최상단의 State값이 변경됨으로써 생기는 사이드이펙트들을 또한 신경써줘야 하는 단점이 있었다. 또한 하나의 View에 여러개의 alert이 필요한 경우 하나의 View 타입에 여러개의 alert을 달아주는 경우 정상적으로 동작하지 않는 경우가 생겨 불필요한 코드들이 추가되기도 한다.

 물론 선언형인 SwiftUI에서 어울리는 방법이긴 하다. 하지만 개인적으로 모든 View에서 매번 저 3가지의 작업을 한다는게 번거롭고 코드의 양도 쓸데없이 커진다는 느낌을 받았다.

 

SwiftUI에서 UIKit

특정 Action을 처리하는 alert인데 굳이 명령형으로 하지 않고 선언형을 사용 할 필요가 있을까?

아래 코드처럼 UIKit를 사용한 AlertController를 만들어 단지 호출만 하여 간단 명료하게 Alert을 표시할 수 있다.

struct BView: View {
	var body: some View {
    	Button(action: { 
        	AlertController.showAlert(
       			title: "알림",
			message: "승인하시겠습니까?",
              	  	primaryAction: { print("승인") }
            )
        }) {
        	Text("show alert!")
        }
    }
}

아래 코드는 가장 상위의 ViewController를 찾은 후 해당 ViewController에 Alert을 추가하는 코드이다.

UIKit의 UIAlertController를 현재 Scene의 가장 상위의 ViewController를 가져와 추가하는 작업이다.

import Foundation
import UIKit

final class AlertController {
    static func showAlert(
        title: String = "알림",
        message: String?,
        primaryAction: @escaping () -> ()
    ) {
        let alert = UIAlertController(
            title: title,
            message: message,
            preferredStyle: .alert
        )
        alert.addAction(
            .init(
                title: "확인",
                style: .default,
                handler: { _ in
                    primaryAction()
                }
            )
        )
        alert.addAction(
            .init(
                title: "취소",
                style: .cancel
            )
        )
        rootController().present(alert, animated: true)
    }
    
    private static func rootController() -> UIViewController {
        guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
            return .init()
        }
        
        guard let root = screen.windows.first?.rootViewController else {
            return .init()
        }
        
        return root
    }
}

 

 

고찰

SwiftUI를 사용하다 보면 참 편한기능이 많고 생산성이 엄청 좋고 유지보수, 코드 관리가 편하다는 것을 느낀다. 하지만 무조건 장점만은 있는게 아니기 때문에 UIKit의 장점과 SwiftUI의 장점을 잘 종합적으로 사용해야 한다는 생각이 든다.

 

 

반응형

Publisher

#Combine #Publisher

Just

  • 가장 단순한 형태의 Publisher 입니다. 에러 타입은 항상 Never 입니다.
    Just((0...5))
      .sink { value in
          print(value) // 0...5
      }

 

Future

  • 일반적으로 Publisher의 처리를 sink 라는 구독을 형태로 많이 처리하게 되는데 이 때 클로저를 전달하는 과정에서 콜백 기반의 completion 핸들러를 사용하게 되는데 Futrue를 통하여 더욱 깔끔한 코드 작성이 가능해 집니다.
  let myFuture = Future<Int, Never> { promise in
      promise(.success(10))
  }
  myFuture.sink { value in
      print(value) // 10
  }
  • URLSeesion 이나 Alamofire 등 RestFul 관련 API 비동기 요청시에 해당 요청이 성공했는지, 실패 했는지에 대한 여부를 리턴해주는 예제 입니다.
func isSuccessAPIRequest() -> AnyPublisher<Bool, Never> { 
    Future<Bool, Never> { promise in 
        urlRequestPublisher
            .sink(
                receiveCompletion: { completion in 
                    switch completion {
                    case .finished: 
                        print("finished")
                        promise(.success(true))
                    case .failure(let error): print(error.localizedDescription)
                        promise(.success(false))
                    }
                }, receiveValue: { value in
                    print(value)
                }
            )
    }
    .eraseToAnyPublisher()
}

isSuccessAPIRequest()
	.sink { 
		if $0 {
			// true
		} else {
			// false
		}
	}

 

Fail

  • 지정한 종류의 에러로 즉시 종료하는 Publisher 입니다.

 

Empty

  • 값을 게시하지 않고 선택적으로 즉시 완료되는 Publisher 입니다.
  Empty<String, Never>()
      .sink(
          receiveCompletion: { 
              print($0) // finished
          },
          receiveValue: {
              print("receiveValue : \($0)") // 출력 안함
          }
      )

 

Deferred

  • 구독이 일어나기 전까지 대기상태로 있다가 구독이 일어 났을 때 Publisher가 결정이 됩니다. 클로저 안에는 지연 실행 할 Publisher 를 반환합니다.
    Deferred { Just(Void()) }
      .sink(receiveValue: { print("Diferred") })

 

Sequence

  • 요소의 주어진 Sequence를 반환하는 Publisher 입니다.
  • Publisher가 Sequence에 있는 요소들을 하나 하나 제공해주며 모든 요소들이 다 제공되었을 때 종료됩니다.
    Publishers.Sequence<[Int], Never>(sequence: [1, 2, 3])
        .sink(receiveValue: { 
            print("Sequence : \($0)")
        })
    /*
     Sequence : 1
     Sequence : 2
     Sequence : 3
     */
반응형

Combine이 가지고 있는 기능들을 정리해보았습니다. 앞으로 해당하는 글을 계속 쓰면서 업데이트 할 예정입니다.

업데이트를 하게되면 해당 설명 아래에 링크를 추가하겠습니다!

 

Publisher 종류 

  1. Just: 위에서 본것과같이 가장 단순한 형태의 Publsiher로 에러타입으로 Never를 갖습니다.
  2. Promise: Just와 비슷하지만 Filter Type을 정의할 수 있습니다.
  3. Fail: 정의된 실패타입을 내보냅니다.
  4. Empty: 어떤 데이터도 발행하지 않는 퍼블리셔로 주로 에러처리나 옵셔널값을 처리할때 사용됩니다.
  5. Sequence: 데이터를 순차적으로 발행하는 Publisher로 (1…10).Publisher로 이에 해당합니다.
  6. ObservableObjectPublisher: SwiftUI에서 사용되는 ObservableObject를 준수하는 퍼블리셔입니다.

 

Swift - Combine의 Publisher 알아보기 Just, Future, Fail, Empty, Deferred, Sequence

Publisher #Combine #Publisher Just 가장 단순한 형태의 Publisher 입니다. 에러 타입은 항상 Never 입니다. Just((0...5)) .sink { value in print(value) // 0...5 } Future 일반적으로 Publisher의 처리를 sin..

todayssky.tistory.com

https://todayssky.tistory.com/17


Operator 종류

  • Mapping Element
    • 데이터를 다른 데이터 타입으로 변형
    • Scan
    • setFailureType
    • map
    • flatMap : 최대수 지정 후 새로운 publisher를 반환, 모든 publisher를 성공적으로 완료해도 전체 스트림은 완료되지 않고 계속 살아있음
  • Filtering
    • 조건에 맞는 데이터만 허용
      • compactMap() : filter에서 Optional제거 → 성공적인 리턴만 반환
      • replaceEmpty : empty일 경우 임의값 출력
      • filter : 기본
      • replaceError
      • removeDuplicates : 중복 제거
  • Reduce
    • 데이터 스트림을 모아서 출력
    • Collect
    • reduce
    • tryReduce
    • ignoreOutput : 입력값을 모두 무시하고 완료 이벤트만 보냄
  • Mathematic operations on
    • 숫자시퀀스값과 관련된 스트림을 제어
    • Max, count, min
  • Sequence
    • 데이터 시퀀스를 변형할때 사용
    • Prepend
    • firstWhere
    • tryFirstWhere
    • first : 클로저의 bool에 일치하는 항목중 첫번째를 가져옴
    • lastWhere
    • tryLastWhere
    • last : 마지막을 가져옴 ( 마지막엔 copletion에 finished를 보내줘야함 )
    • dropWhile : true가 될때까지 drop, true 이후로 출력(포함)
      • filter와의 차이점 : filter는 모든 데이터가 해당 조건문을 비교해야함
    • prefix : prefix(2) 두 값을 내보내면 publisher가 완료됨
    • prefix(while: {} ) : 클로저의 결과가 true일 경우 완료
    • prefix(untilOutputFrom: ) : 해당 신호가 오면 완료
    • → prefix는 drop과 반대 개념인것 같음

연산자 결합

  • prepend : 먼저 추가 후 publisher 완료
  • append : 완료 한 후 항목 추가
  • swiftchToLatest() : publisher가 바뀌면 이전 subscribe 취소
  • merge(with:) : 병합
  • combineLatest : 결합 → 타입이 달라도 됨 (한 쌍이 도착할 때 마다 한쪽이 기다림)

Time 연산자

  • delay : 지정 시간(초) 만큼 딜레이를 준 후 값을 보냄
  • collect(.byTime) : 지정 시간만큼 기다린 후 배열로 모아서 보냄
  • debounce : 지정 시간을 기다린 후 출력 (일시정지)
  • throttle : 지정 시간을 기다린 후 가장 최신 값을 출력 ( 일시정지 x)
    • share() 연산자를 추가하면 모든 구독자가 동일한 출력을 동시에 볼 수 있음
    • debounce와 비슷하지만 다름 (차이점?)
  • subject.timeout : 마지막 응답 후 지정 시간이 지나면 게시가자 완료됨
  • subject.measureInterval : 시간 간격 출력

Sequence 연산자

  • min : 완료 이벤트를 수신한 후 최소값을 구함
    • Comparable 프로토콜을 준수하지 않으면 min(by:) 클로저를 구현해야함
  • max : min과 같이 완료 이벤트를 수신한 후 최대값을 구함
  • first() : 첫번째값만 받고 구독취소
    • .(where:) : 해당하는 첫번째 값을 받음
  • last() : finished를 기다린 후 마지막 인자를 받음
  • output(at :) : 해당 인덱스에 해당하는 순서까지 받음 (구독 취소됨) , (in:) : 해당 범위

publisher query

  • count()
  • contains() : bool을 반환 , where 사용
  • allStatisy : contains의 전체버전 ( 하나라도 false시 즉시 구독 해제 및 false 리턴 )
  • reudce( { } ) : 단일값을 반환

Subject

  • publisher의 일종
  • 외부의 데이터를 안으로 주입시킬 수 있음 → SwiftUI같은 다른 Framework와도 쉽게 연동 가능
  • PassthroughSubject
    • 상태값을 가지지 않음
  • CurrentValueSubject
    • 상태값을 가짐
    • UI 상태값에 따라 데이터를 발행할 때 유용

Cancellable

  • Subscriber의 리턴값
  • cancle() 메서드로 스트림 중단 가능

eraseToAnyPublisher

  • 데이터 스트림과 상관없이 최종적인 형태의 Publisher를 리턴

리소스 관리

  • share()
  • multicast
  • future class

사용할만한 소스

  • 시간 간격 출력
class TimeLogger: TextOutputStream {
  private var previous = Date()
  private let formatter = NumberFormatter()

  init() {
    formatter.maximumFractionDigits = 5
    formatter.minimumFractionDigits = 5
  }

  func write(_ string: String) {
    let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines)
    guard !trimmed.isEmpty else { return }
    let now = Date()
    print("+\(formatter.string(for: now.timeIntervalSince(previous))!)s: \(string)")
    previous = now
  }
}

/* ex)
let subscription = (1...3).publisher
  .print("publisher", to: TimeLogger())
  .sink { _ in }
*/
  • http decode
func story(id: Int) -> AnyPublisher<Story, Error> {
  URLSession.shared
    .dataTaskPublisher(for: EndPoint.story(id).url)
    .receive(on: apiQueue)  // 수신할 스케줄러를 정의
    .map(\.data)
    .decode(type: Story.self, decoder: decoder)
    .catch { _ in Empty<Story, Error>() } // 게시자의 오류를 다른 게시자로 대체
    .eraseToAnyPublisher()
}

// 커스텀 디버그 스트링
extension Story: CustomDebugStringConvertible {
  public var debugDescription: String {
    return "\n\(title)\nby \(by)\n\(url)\n\(id)\n\(time)\n-----"
  }
}
반응형

SwiftUI에서 UIkit 사용하기


SwiftUI에서 UIkit를 사용하기 위해서는 UIViewRepresentable을 채택하는 struct를 구현하면 됩니다.

UIViewRepresentable을 채택하게 되면 필수로 구현해야 하는 makeUIView와 updateUIView가 있고 UIViewType을 원하는 UIkit의 View로 변경하면 됩니다.

UIViewRepresentable

// 구현
struct SwiftUIView: UIViewRepresentable {
	func makeUIView(context: Context) -> UIViewType {
    	let view = UIViewType()
        return view
    }
    
    func updateUIView(_ view: UIViewType, context: Context) {
    
    }
}


// 사용
struct MyView: View {
	var body: some View {
    	VStack { 
        	SwiftUIView()
        }
    }
}

UIViewControllerRepresentable

만약 Custom View가 아닌 하나의 Controller일때는 UIViewControllerRepresentable이라는 것을 따로 제공합니다. 

makeUIViewController에 해당하는 ViewController를 리턴하도록 해주면 됩니다.

struct MyViewControllerRepresentation: UIViewControllerRepresentable { 
	func makeUIViewController(context: Context) -> ViewController {
		
    }

	func updateUIViewController(_ uiViewController: ViewController, context: Context) { 
    
    } 
}

 

 

SwiftUI에서 Storyboard 사용하기


코드로 구현된 UIViewController가 아닌 Storyboard(.xib)로 구현되어있다면 어떻게 해야할까요?

UIStoryboard

struct MyViewControllerRepresentation: UIViewControllerRepresentable { 
	func makeUIViewController(context: Context) -> ViewController {
		UIStoryboard(name: "MyStoryBoardView", bundle: nil)
        	.instantiateViewController(withIdentifier: "ViewController") as! ViewController
    }

	func updateUIViewController(_ uiViewController: ViewController, context: Context) { 
    
    } 
}



반응형

+ Recent posts