전에 iOS6 회전에 관련한 글을 올렸었다.

http://devnote2.tistory.com/entry/iOS6-shouldAutorotateToInterfaceOrientation-문제
http://devnote2.tistory.com/entry/iOS6-shouldAutorotateToInterfaceOrientation-문제2

위 문제 외 한가지 더 확인해야 될 상황이 생겼다. 기존 구조에서는 NavigationController를 상속 받아 모달에 넣어 띄우는 것을 기본으로 사용하여 이번에 생긴 문제를 제대로 확인 하지 못했는데 다시 테스트 해보니 navigationController의 회전 설정 값이 우선되어 하위 ViewController의 값이 제대로 적용되지 않았다.

즉 NavigationController의 shouldAutorotate 값이 하위 뷰컨트롤러의 값을 호출하지 못해 회전값을 뷰컨트롤러 단위로 설정하기 어려운 상황이였다.

즉 따로 UINavigationController를 상속받아 회전값을 설정하는 방법외에 기본 UINavigationController로만 회전 값을 제어하기 위해서 알아본 결과 카테고리를 통해 하위 UIViewController에서 UINavigationController의 shouldAutorotate 함수를 덮어 기능을 제한하는 방법이 가장 간편한 방법을 것같다.

아래의 테스트 코드로 확인하였다.

#import "ViewController.h"

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
   
    self.view.backgroundColor = [UIColor whiteColor];
 // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(BOOL) shouldAutorotate {
    return NO;
}

-(NSUInteger) supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

@end

 

즉 UINavigationController의 shouldAutorotate 가 실행될 때 하위뷰에서 그 메소드를 후킹(?) 해서 회전 값에 대한 정보를 변경하는 것이 포인트이다.

 

이번 ios6 업데이트로 인해 앱을 확인한 결과 shouldAutorotateToInterfaceOrientation의 deprecate로 인해 viewController가 제대로 작동하지 않음을 확인하였다.

그래서 해결 방법을 찾기위해 릴리즈 노트를 확인해본 결과

- (BOOL)shouldAutorotate;

메소드를 사용하여 자동회전 여부에 대한 값을 반환하면 되다고 하였다.

하지만 해당 메소드를 사용하고도 제대로 회전이 되지 않아 다시 릴리즈 노트를 꼼꼼히 본 결과 뭔가 다른 원인이 있다는 생각이 들었다.

그래서 ios6용 테스트 프로젝트용을 생성하고 나서 appDelegate 부터 확인해본 결과 이외로 간단한 곳이 문제였다.

기존 ios5 까지는 앱을 실행할때 appDelegate 내 window 객체에 UIViewController의 view를 addSubview하는 방식으로 사용하였다.

[self.window addSubview:self.rootViewController.view];

하지만 ios6의 내용을 보니 아래와 같았다

self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = self.rootViewController;

즉 ios6에서는 UIWindow객체를 생성하여 할당한 다음에 rootviewController 프로퍼티에 해당 뷰를 넣어주면 었다.

아래의 방식으로 앱을 변경하고 실행해보니 기존 처럼 자동회전이 동작하였다. 아마 자동회전에 대한 변경된 로직이 UIWindow서 부터 무엇인가 바껴서 이렇게 방식이 변경된 듯 싶다

그리고 기존 shouldAutorotateToInterfaceOrientation는 앱이 viewDidLoad되고 나서 한번 실행된 후 회전이 있을 때 마다 실행이 되었다면

shouldAutorotate은 처음 load될때 한번 실행된다. 이후 회전에 대한 뷰의 위치 변경은

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration ;

메소드를 사용하여 동일한 동작을 얻을 수 있었다.

한가지 주의할 점은 appDelegate내 시작 방식을 변경할 때 sdk버전을 잘 확인해야 한다.

단말기가 6.0이고 sdk가 5.1 일 경우 위 방식대로 하게 되면 아무 화면도 뜨지 않는 결가가 생긴다. 이건 5.1이하에서는 6.0 방식이 제대로 호환이 안되는 것 같으니 주의해야 한다.

+ Recent posts