0x00 引入
蘋果沒有公開強制設置物理設備方向的方法。
SO上能找到的最多的方法是:
NSNumber orientation = [NSNumber numberWithInt:targetOrientation];
[[UIDevice currentDevice] setValue:orientation forKey:@"orientation"]
這種方法使用KVO機制,間接地使用了蘋果的私有方法。不過多次實測驗證不影響上架審核。
0x01 問題
上述setValue:forKey:方法有一個問題,如果將要設置的目標方向與當前物理設備的方向一樣的話,上述方法可能會不起作用。
例如:兩個視圖控制器A和B,其中A支持橫屏和豎屏, B僅支持橫屏,當從Portrait方向由 A push到 B時,強制設置B的方向為LandscapeRight,從B返回到A時,我們還希望A是Portrait方向。但是如果我們在B視圖控制器上把設備旋轉至Portrait方向時,然后在返回A,使用上述setValue:forKey:的方法強制把物理設備方向設置為Portrait時就會不起作用,因為此時物理設備的方向與將要設置的目標方向是一樣的。
0x02 原因猜想
如果當前物理設備的方向與要設置的目標方向一致時,系統可能覺得沒有必要進行任何操作(按照正常的邏輯來考慮,好像應該是這樣),在系統內部實現上可能就直接return了(未考證,猜測)。然而業務的需求常常會不僅僅于此,我們期望能在任意當前方向把物理設備設置為任意目標方向。
0x03 問題解決
既然直接通過setValue:forKey:設置目標方向不起作用,那么猜想可以先設置一個unknown方向欺騙系統,然后再設置目標方向,這時目標方向跟unknown方向是不同,系統就會生效這種設置。
下面是一個強制設置設備方向的方法:
- (void)forceToOrientation:(UIDeviceOrientation)orientation
{
NSNumber *orientationUnknown = [NSNumber numberWithInt:0];
[[UIDevice currentDevice] setValue:orientationUnknown forKey:@"orientation"];
NSNumber *orientationTarget = [NSNumber numberWithInt:orientation];
[[UIDevice currentDevice] setValue:orientationTarget forKey:@"orientation"];
}
在iOS7,8,9上驗證,可以完美解決0x01例子中的問題。
在蘋果不提供有效的公開API時,這種方法基本可以達到這樣的目標:在任意當前方向把物理設備設置為任意目標方向。