안녕하세요 🐶
빈 지식 채우기의 비니🙋🏻♂️ 입니다.
오늘은 Trouble Shooting의 첫 번째 시간입니다.
바로 코드를 통해 iOS 16에서 강제로 단말기 Orientation 을 변경하려고 할때 생기는 이슈에 대해 말씀드리려고 해요~
1. 공통
실제로 단말기의 Orientation을 변경하는 부분은 Appdelegate에서 구현이 가능합니다.
iOS16 이전 이후 Appdelegate에 구현된 소스는 동일하게 사용 가능합니다.
바로 코드를 통해 알아보도록 하겠습니다.
enum orientationType: Int { // (1)
case all = 0
case portrait
case landscape
}
var orientation:orientationType = .all // (2)
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
var device:UIInterfaceOrientationMask = .all // 해당 함수에서 반환할 변수 선언
device = {
switch orientation {
case .portrait:
return .portrait
case .landscape:
return .landscapeLeft
default:
return .all
}
}() // (3)
return device // (4)
}
- enum ( 열거형 ) 을 사용하여 orientationType을 정의합니다.
- enum으로 만든 orientationType타입의 orientation 변수를 선언합니다.
- 기본은 .all을 선언합니다. ( 가로 세로 가능 )
- orientation 값에 따라 portrait 인지 landscape 인지 판별합니다.
- orientation 값의 변화는 하단 소스로 확인할 수 있습니다.
- device ( UIInterfaceOrientationMask ) 값을 반환합니다.
2. iOS 16 이전
UIDevice.current.setValue를 통해 Orientation 변경 로직을 구현을 했었습니다.
바로 코드를 통해 알아보도록 하겠습니다.
func changeOrientation(type: orientationType) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.orientation = .portrait // (1)
var value = UIInterfaceOrientation.portrait.rawValue // rawValue로 선언
if type == .landscape {
value = UIInterfaceOrientation.landscapeRight.rawValue // (2)
appDelegate.orientation = .landscape // (3)
}
UIDevice.current.setValue(value, forKey: "orientation") // (4)
}
- AppDelegate에서 정의한 orientation에 portrait을 부여합니다.
- 기본으로 세로모드로 정의 후 type에 따라 재 정의합니다.
- type이 landscape일 경우 landscape rawValue로 변경해줍니다.
- 이때 AppDelegate에 선언한 orientation에 landscape로 변경해줍니다.
- UIDevice 싱글톤 객체의 setValue를 통해 orientation 값을 저장합니다.
- Key 값은 "orientation" 을 사용합니다.
- 해당 메서드를 호출을 해야만 AppDelegate에서 선언한 supportedInterfaceOrientationsFor이 호출이 됩니다.
해당 로직 실행 후 AppDelegate의 supportedInterfaceOrientationsFor가 호출이 되면서 단말기의 Orientation이 변경이 됩니다.
하지만!!!!!!!
iOS16 부터는 위와 같이 실행 시 아무런 동작을 하지 않습니다. 그리고 아래와 같은 경고 메세지도 표시가 됩니다.
[Orientation] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)
그렇기 때문에 iOS16에서는 다른 식으로 구현을 해야 합니다.
아오 귀찮아.. 그냥 쓰지
3. iOS 16 이후
UIWindowScene의 requestGeometryUpdate을 사용하여 변경 로직을 구현합니다.
아몰랑 바로 소스로 가보겠습니다.
func changeOrientation(type: orientationType) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.orientation = .portrait
var value = UIInterfaceOrientationMask.portrait
if ["land", "landscape"].contains(type) {
value = UIInterfaceOrientationMask.landscapeLeft
}
DispatchQueue.main.async {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene // (1)
vc.setNeedsUpdateOfSupportedInterfaceOrientations() // (2)
windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: value)) { error in
BMCLog.error(error)
BMCLog.error(windowScene?.effectiveGeometry ?? "") // (3)
}
}
}
- UIApplication 싱글통 객체를 사용하여 UIWindowScene을 가져옵니다.
현재 ViewController 에게 나! Orientation 변경할꺼야 그렇게 알아 라고 통보합니다.
- 해당 메서드를 호출을 해야만 AppDelegate에서 선언한 supportedInterfaceOrientationsFor이 호출이 됩니다.
지원되는 인터페이스 방향 또는 프리젠테이션을 위한 기본 인터페이스 방향의 변경에 대해 VC에 알립니다.
설명을 보면 지원 범위가 16.0 이상부터 라고 되어 있습니다.
16.0 이상부터 Orientation 인터페이스를 변경하기 위해서는 해당 메서드를 사용해야 합니다.
3. UIApplication을 통해 가져온 UIWindowScence를 통해 requestGeometryUpdate 메서드를 호출합니다.
지정된 지오메트리 기본 설정 개체를 사용하여 창 장면의 지오메트리에 대한 업데이트를 요청합니다.
...무..무슨소리..?
그니까 해당 함수를 통해 명시적으로 Orientation 변경을 요청합니다.
( 이 부분에 대해서는 좀 더 공부가 필요할 것 같습니다. 잘 아시는 분은 댓글로 남겨주세요~ )
이상으로 Device Orientation 변경하기 포스팅을 마치겠습니다.
iOS16 이상부터 변경하는 방식이 바뀌었다는걸 오늘 알아서 후다닥 포스팅을 해보았습니다.
틀린 부분이나 궁금한 사항은 댓글 남겨주세요~
참고
'iOS 🖥️ > Trouble Shooting' 카테고리의 다른 글
[TS - iOS] NWProtocolTCP.Options() - EXC_BAD_ACCESS (0) | 2024.07.04 |
---|---|
[TS - iOS] Ignoring ffi-1.15.5 because its extensions are not built 이슈 (0) | 2024.02.20 |
[TS - iOS] DT_TOOLCHAIN_DIR cannot be used to evaluate 이슈 (0) | 2024.02.20 |