私は Objective-C を初めて使用するので、この長い説明をご容赦ください。他の初心者の助けになることを願っています。既存の iPad アプリにいくつかの変更を加えることに成功しました。ただし、元のインストール/更新ルーチンは、時間内に起動できなかったという障壁にぶつかっています。ここの投稿は、問題と調査する方向を理解するのに大いに役立ちました。
初心者向けのグローバルな行ごとのソリューションが見つからなかったため、ここや他の場所のさまざまな投稿からソリューションをまとめました。
データベースの初期化/更新を didFinishLaunchingWithOptions から引き出し、インスタンス化された UIViewController を使用してここからできるだけ早く戻る必要があることを理解しています。
ここで通常呼び出される rootVC は、データの準備が整っておらず完全でない場合は初期化できないことに注意してください。rootVC が最初にそこに到達し、必要なデータが見つからないときに爆発するため、DB ルーチンを非同期にするだけでは役に立ちません。
つまり、必要なことを平和に行っている間、rootVC を遅らせる必要があります。シームレスになるように UILaunchImage をロードし、スピナーを追加することにしました。
質問は:
1) 噛まれたり 8badf00d になったりしないように、特に他の副作用を追加することなく、正しく実行しましたか? それとも、おそらく既存の rootVC のラッパー init メソッドでそれを行うべきでしたか?
2) dealloc、rootViewController、または splashViewController はどうですか? この段階ではむしろ rootViewController だと思います。混乱している。
3) 動作しますが、これは実際に、rootVC として rootViewController によって、splashViewController を置き換え (および削除) していますか? それとも積み上げてるのか…
前
RAppDelegate.h
#import <UIKit/UIKit.h>
#import "RDataManager.h"
#import "RRootViewController.h"
#import "RScreenViewController.h"
@interface RAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
RRootViewController *rootViewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, readonly) RRootViewController *rootViewController;
@end
RAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[RDataManager sharedManager] updateDatabase]; // This is what takes time...
rootViewController = [[RRootViewController alloc] initAtScreen:kScreenTypeIndex withCar:carId];
rootViewController.wantsFullScreenLayout = YES;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
...
- (void)dealloc
{
[rootViewController.view removeFromSuperview];
[rootViewController release];
[window release];
[super dealloc];
}
後
RAppDelegate.h
#import <UIKit/UIKit.h>
#import "RDataManager.h"
#import "RScreenViewController.h"
#import "RSplashViewController.h"
@interface RAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
RSplashViewController *splashViewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, readonly) RSplashViewController *splashViewController;
@end
RAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
splashViewController = [[RSplashViewController alloc] init];
splashViewController.wantsFullScreenLayout = YES;
self.window.rootViewController = splashViewController;
[self.window makeKeyAndVisible];
return YES;
}
...
- (void)dealloc
{
[splashViewController.view removeFromSuperview];
[splashViewController release];
[window release];
[super dealloc];
}
RSplashViewController.h
#import <UIKit/UIKit.h>
#import "RRootViewController.h"
@interface RSplashViewController : UIViewController
{
UIImageView *splashImageView;
RRootViewController *rootViewController;
UIActivityIndicatorView *spinner;
}
@property (nonatomic, retain) UIImageView *splashImageView;
@property (nonatomic, readonly) RRootViewController *rootViewController;
@end
RSplashViewController.m
#import "RSplashViewController.h"
#import "RDataManager.h"
@interface RSplashViewController ()
@end
@implementation RSplashViewController
@synthesize splashImageView;
@synthesize rootViewController;
- (void) loadView
{
CGRect appFrame = [UIInterface frame];
UIView *view = [[UIView alloc] initWithFrame:appFrame];
self.view = view;
[view release];
NSString *splashFile = [[NSBundle mainBundle] pathForResource:@"LaunchImage-jaguar-Landscape~ipad" ofType:@"png"];
UIImage *splashImage = [[UIImage alloc] initWithContentsOfFile:splashFile];
splashImageView = [[UIImageView alloc] initWithImage:splashImage];
[self.view addSubview:splashImageView];
[splashImage release];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
CGRect frame = spinner.frame;
frame.origin.x = CGRectGetMidX(self.view.frame) - CGRectGetWidth(spinner.frame) / 2;
frame.origin.y = 650;
spinner.frame = frame;
spinner.hidesWhenStopped = YES;
[self.view addSubview:spinner];
[spinner startAnimating];
}
- (void) viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// how we stop DB refresh from freezing the main UI thread
dispatch_queue_t updateQueue = dispatch_queue_create("updateDB", NULL);
dispatch_async(updateQueue, ^{
// do our long running process here
[[RDataManager sharedManager] updateDatabase];
// do any UI stuff on the main UI thread
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[splashImageView removeFromSuperview];
rootViewController = [[RRootViewController alloc] initAtScreen:kScreenTypeGarage withCar:nil needSplashScreen:YES];
[self.view addSubview:rootViewController.view];
});
});
dispatch_release(updateQueue);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) dealloc
{
[super dealloc];
}
@end