2026年05月09日

UIKit scene-based life cycleへのマイグレーション Objective-c Xib版

iOS27より、UISceneライフサイクルでアプリを起動しない場合、アプリが起動しないことがAppleより正式に告知がなされた。

TN3187: Migrating to the UIKit scene-based life cycle
https://developer.apple.com/documentation/technotes/tn3187-migrating-to-the-uikit-scene-based-life-cycle#Provide-scene-configurations-from-your-app-delegate-for-dynamic-configuration

従来のAppDelegateでUI構築を実装しているアプリは、SceneDelegateでUI構築を実装するようにコード修正を行う必要がある。

Swiftで記述されたアプリは、Appleが公開しているマイグレーションガイドや公開されている個人デベロッパーや法人ブログを参考にしながら容易に可能だが、Objective-cで記述されたレガシーなアプリについてのマイグレーションガイドは現時点において、Meduimで公開されている個人執筆の記事しか存在しない。

App Storeで配信されているアプリには、Objective-cで記述されたレガシーなアプリが相当数あると推測され、iOS27の正式リリースより前に早めに対応することが推奨される。

本記事では、Objective-cで記述されたアプリで、画面定義にxibを使用した場合のscene-based life cycleへのマイグレーション手順を記述する。


1. info.plistの修正
UIApplicationSceneManifestキーを追加する。
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>

Apple公式のマイグレーションガイドには、UISceneDelegateClassNameは$(PRODUCT_MODULE_NAME).SceneDelegateと記されているが、Objective-cで記述されたレガシーなアプリの場合は、
SceneDelegate
と記述し、後述するようにSceneDelegateクラスを定義する。

Apple公式のマイグレーションガイドでは、UISceneStoryboardFileを指定するようになっているが、画面定義にはStoryboardではなくXibを使用しているので、UISceneStoryboardFileキーは不要である。
Apple公式のマイグレーションガイドでは、UISceneDelegateClassNameキーの記述はないが、Xcodeでinfo.plistにUIApplicationSceneManifestキーを追加すると、UISceneClassNameキーが自動で追加される。
しかしながら、Objective-c XibのUIKit scene-based life cycleへの移行時はUISceneClassNameキーは不要なので削除すること。

アプリで使用する画面の構成定義(以降「UIのセットアップ」と称する)は、移行前のAppDelegateで記述しているコードをコピーしてSceneDelegateで記述する。

info.plistにUIApplicationSceneManifestキーを定義しない場合は、AppDelegateに下記のメソッドを記述してUISceneConfigurationをコードにより記述する。
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {

// Create a name for the configuration
NSString *configurationName = @"Default Configuration";

// Make a new configuration
UISceneConfiguration *configuration = [[UISceneConfiguration alloc] initWithName: configurationName sessionRole: connectingSceneSession.role];

return configuration;
}

このメソッドは、info.plistにUIApplicationSceneManifestが含まれていない場合に呼ばれる。info.plistにUIApplicationSceneManifestキーがある場合はこのメソッドは呼ばれない。
iOSは、info.plistにUIApplicationSceneManifestキーが記述されているか、AppDelegateにapplication:configurationForConnectingSceneSession:options:メソッドが記述されている場合に、UISceneライフサイクルでアプリを起動する。

info.plistにUIApplicationSceneManifestキーを定義するか、configurationForConnectingSceneSessionメソッドにUISceneConfigurationをコードで記述するか、どちらか一方にすること。
info.plistにUIApplicationSceneManifestキーが定義されていれば、configurationForConnectingSceneSessionメソッドが定義されていても呼ばれないのが正しい動作だが、iOS26.4.2ではconfigurationForConnectingSceneSessionメソッドが呼ばれたり、呼ばれなかったりするバグがある。


2. ScneDelegateでUIのセットアップ記述
ScneDelegate.h
#import
@interface SceneDelegate : UIResponder

@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskIdentifier;

@end


ScneDelegate.m
@implementation SceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
// Make sure the scene is of type UIWindowScene.
// UIWindowScene is inherited from UIScene, so this check should always pass
if (![scene isKindOfClass: [UIWindowScene class]]) {
return;
}

// Make a new window scene by casting 'scene' to a UIWindowScene
UIWindowScene *windowScene = (UIWindowScene *) scene;

// Make a new window, initialized with the window scene.
self.window = [[UIWindow alloc] initWithWindowScene: windowScene];

// App Delegateのapplication:didFinishLaunchingWithOptions:で記述しているUI構築コードをここにコピーする




// Create view controller
ViewController *homeViewController = [[ViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: homeViewController];

// Assign root view controller
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
}

開発しているアプリのUIに合わせて、UITabBarControllerやUINavigationControllerの定義を記述すること。App Delegateで記述した定義と同一でよい。

self.window.rootViewControllerへのNavigationControllerの設定は、開発しているアプリのUIに合わせて修正すること。


3. ScneDelegateでアプリ起動時、バックグラウンド移行時、バックグラウンドからの復帰時のコード記述
AppDelegateで定義していたUIApplicationDelegate のapplicationDidEnterBackgroundapplicationWillResignActiveなどは呼ばれなくなり、対応するUISceneDelegateのメソッドに呼ばれる。
- (void)sceneDidEnterBackground:(UIScene *)scene {
// 1. バックグラウンドタスクを開始する
self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// 2. 時間制限(通常30秒〜数分)までに終了しなかった場合、ここが呼ばれる
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];
}

- (void)sceneWillResignActive:(UIScene *)scene {

}

- (void)sceneWillEnterForeground:(UIScene *)scene {

}

- (void)sceneDidBecomeActive:(UIScene *)scene {

}

AppDelegateで定義していたアプリ起動時、バックグラウンド移行時、バックグラウンドからの復帰時のコードは、これらのメソッドに記述する。


4. App Delagateの修正
App Delegateのapplication:didFinishLaunchingWithOptions:で記述しているUIのセットアップコードはコメントアウトするか、削除する。

scene-based life cycleに移行しても、AppDelegateのapplication:didFinishLaunchingWithOptionsは呼ばれる。
UIのセットアップとアプリ起動時、バックグラウンド移行時、バックグラウンドからの復帰時のコードはSceneDelegateで実行し、それ以外の初期設定は従来通りAppDelegateで実行するようにする。


参考記事:
Apple Developer
https://developer.apple.com/documentation/technotes/tn3187-migrating-to-the-uikit-scene-based-life-cycle

Objective-c Migration
https://medium.com/@teakelld/migrating-to-uikit-scene-based-life-cycle-in-objective-c-f1a2f9402e24

日本語解説ブログ
https://dev.classmethod.jp/articles/ios27-xcode27-migration-preparation-guide/
https://techblog.lycorp.co.jp/ja/20250619a
https://buildersbox.corp-sansan.com/entry/2026/03/09/100000
https://product.st.inc/entry/2025/09/29/174637
https://zenn.dev/oka_yuuji/articles/ff6b0e1bd76566
posted by mobileDeveloper at 14:47 | Comment(0) | TrackBack(0) | UIScene | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック