我是Objective-c的新手,请耐心等待这个冗长的解释,希望对其他初学者有所帮助。我已经成功地对现有iPad应用程序进行了一些更改。但是,原始的安装/更新例程已无法及时启动。此处的帖子极大地帮助了我了解了问题以及研究的方向。
由于找不到针对初学者的逐行全局解决方案,因此我在这里和其他地方的不同文章中都编写了解决方案。
我了解我需要从didFinishLaunchingWithOptions中拉出数据库init / update,并从此处以实例化的UIViewController尽快返回,该UIViewController将使数据库脱离主线程(感谢主题的所有发布者)。
请注意,如果数据尚未准备好且完好无损,则通常在此处调用的rootVC无法初始化。因此,仅对DB例程执行异步操作无济于事,因为rootVC首先到达那里,并在找不到所需数据时爆炸。
即我需要延迟rootVC,同时我们需要做和平地做任何我们需要做的。我选择加载UILaunchImage以使其无缝,并添加一个微调器。
问题是:
1)我是否已正确完成操作,以使我再也不会被咬伤和8badf00d了,尤其是不增加其他副作用的情况下?还是应该以其他方式进行操作,也许是在现有rootVC的包装器init方法中?
2)那dealloc,rootViewController或splashViewController呢?我认为到这个阶段它是rootViewController。困惑。
3)它可以工作,但是这真的是由rootViewController作为rootVC替换(并删除)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
最佳答案
回答我的问题。
1)是的,使用SplashViewController或rootVC初始化包装器,这是安全的。临时运行2分钟没有问题。仔细检查更新是否确实在单独的线程中运行(Xcode调试窗口窗格)。
2)自从我移到rootVC初始化包装器解决方案并恢复为取消分配rootViewController以来,没有问题。
3)2)解决的问题。
我还设法将更新时间减少了90%,无论如何这都是理想的解决方案,但是很高兴知道我也安全地摆脱了看门狗计时器的困扰。