我是objective-c的新手,所以请耐心等待这个冗长的解释,我希望它对其他初学者有所帮助。我已经成功地对现有的 iPad 应用程序进行了一些更改。但是,最初的安装/更新例程遇到了未能及时启动的障碍。这里的帖子极大地帮助了我理解问题以及研究的方向。
我已经从这里和其他地方的不同帖子中编译了一个解决方案,因为我没有为初学者找到一个全局的逐行解决方案。
我知道我需要从 didFinishLaunchingWithOptions 中提取数据库初始化/更新,并尽快从这里返回一个实例化的 UIViewController,该 UIViewController 将在主线程之外执行数据库内容(感谢有关该主题的所有海报)。
请注意,如果数据未准备好且完整,则通常在此处调用的 rootVC 无法初始化。因此,仅在 DB 例程上进行异步对我没有帮助,因为 rootVC 会先到达那里,然后在找不到所需的数据时就崩溃了。
即我需要延迟rootVC,而我们需要做任何我们需要做的事情,并且很平静。我选择无缝加载 UILaunchImage 并添加一个微调器。
问题是:
1) 我是否做得正确,这样我就不会再被咬和 8badf00d 了,尤其是在没有增加其他副作用的情况下?或者我应该以其他方式完成它,也许在现有 rootVC 的包装器 init 方法中?
2)dealloc、rootViewController或splashViewController呢?我认为在这个阶段它是相当 rootViewController 。使困惑。
3)它可以工作,但这真的用rootViewController替换(和删除)splashViewController作为rootVC吗?还是我把它们堆起来...
前
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