mamaral / Onboard

An iOS framework to easily create a beautiful and engaging onboarding experience with only a few lines of code.
MIT License
6.46k stars 765 forks source link

Don't work onboard in my app #12

Closed pavkosykh closed 10 years ago

pavkosykh commented 10 years ago

I'm wrote appDelegate.m like this.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"IPhone"    bundle: nil];
    SidebarViewController *rightMenu = (SidebarViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: @"sidebar"];
    [SlideNavigationController sharedInstance].rightMenu = rightMenu;

    // Creating a custom bar button for right menu
        UIButton *button  = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 22, 22)];
    [button setImage:[UIImage imageNamed:@"submenu"] forState:UIControlStateNormal];
    [button addTarget:[SlideNavigationController sharedInstance] action:@selector(toggleRightMenu) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
    [SlideNavigationController sharedInstance].rightBarButtonItem = rightBarButtonItem;
        [SlideNavigationController sharedInstance].enableShadow = NO;

    //set white text color for status-bar
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 

    BOOL userHasOnboarded = [[NSUserDefaults standardUserDefaults] boolForKey:kUserHasOnboardedKey];

    if (userHasOnboarded) {
        [self setupNormalRootViewControllerAnimated:NO];
    } else {
        self.window.rootViewController = [self generateFirstDemoVC];
    }

    //set font and style for navigation bar
    [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:38.0f/255.0f green:38.0f/255.0f blue:47.0f/255.0f alpha:1.0f]];
    [[UINavigationBar appearance] setTitleTextAttributes:@{
                                                           NSForegroundColorAttributeName: [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f],
                                                           NSFontAttributeName: [UIFont fontWithName:@"ProximaNova-Regular" size:15]
                                                           }];

    [Appirater appLaunched:YES];
    [Appirater setAppId:@"552035781"];
    [Appirater setDaysUntilPrompt:1];
    [Appirater setUsesUntilPrompt:10];
    [Appirater setSignificantEventsUntilPrompt:-1];
    [Appirater setTimeBeforeReminding:2];
    [Appirater setDebug:YES];

    return YES;
}

- (void)setupNormalRootViewControllerAnimated:(BOOL)animated {
    // create whatever your root view controller is going to be, in this case just a simple view controller
    // wrapped in a navigation controller
    NSString *lib = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *file = [lib stringByAppendingPathComponent:@"Metro0_1.sqlite"];
    if(![[NSFileManager defaultManager] fileExistsAtPath:file]) {

        id dbInBundle = [[NSBundle mainBundle] pathForResource:@"Metro0_1" ofType:@"sqlite"];

        [[NSFileManager defaultManager] createDirectoryAtPath:lib withIntermediateDirectories:YES attributes:nil error:nil];
        [[NSFileManager defaultManager] copyItemAtPath:dbInBundle toPath:file error:nil];
    }

    UINavigationController *navigationController =(UINavigationController *)self.window.rootViewController;
    MainViewController *controller = (MainViewController *)navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
    // if we want to animate the transition, do it
    if (animated) {
        [UIView transitionWithView:self.window duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
            self.window.rootViewController = controller;
        } completion:nil];
    }

    // otherwise just set the root view controller normally without animation
    else {
        self.window.rootViewController = controller;
    }
}

- (void)handleOnboardingCompletion {
    // set that we have completed onboarding so we only do it once
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kUserHasOnboardedKey];

    // animate the transition to the main application
    [self setupNormalRootViewControllerAnimated:NO];
}

- (OnboardingViewController *)generateFirstDemoVC {
    OnboardingContentViewController *firstPage = [[OnboardingContentViewController alloc] initWithTitle:@"What A Beautiful Photo" body:@"This city background image is so beautiful." image:[UIImage imageNamed:@"blue"] buttonText:@"Enable Location Services" action:^{
        [[[UIAlertView alloc] initWithTitle:nil message:@"Here you can prompt users for various application permissions." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    }];

    OnboardingContentViewController *secondPage = [[OnboardingContentViewController alloc] initWithTitle:@"I'm so sorry" body:@"I can't get over the nice blurry background photo." image:[UIImage imageNamed:@"red"] buttonText:@"Connect With Facebook" action:^{
        [[[UIAlertView alloc] initWithTitle:nil message:@"Prompt users to do other cool things on startup." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    }];

    OnboardingContentViewController *thirdPage = [[OnboardingContentViewController alloc] initWithTitle:@"Seriously Though" body:@"Kudos to the photographer." image:[UIImage imageNamed:@"yellow"] buttonText:@"Get Started" action:^{
        [self handleOnboardingCompletion];
    }];

    OnboardingViewController *onboardingVC = [[OnboardingViewController alloc] initWithBackgroundImage:[UIImage imageNamed:@"street"] contents:@[firstPage, secondPage, thirdPage]];

    // If you want to allow skipping the onboarding process, enable skipping and set a block to be executed
    // when the user hits the skip button.
    onboardingVC.allowSkipping = YES;
    onboardingVC.skipHandler = ^{
        [self handleOnboardingCompletion];
    };

    return onboardingVC;
}

Onboard download, but then I tap skip button or "Get start" on last screen, Xcode throw exception and terminating my app

-[OnboardingViewController topViewController]: unrecognized selector sent to instance 0x16567d10

 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[OnboardingViewController topViewController]: unrecognized selector sent to instance 0x16567d10'

What's wrong with me?)

mamaral commented 10 years ago

Based on the error my guess is the issue is related to the following lines of code:

UINavigationController *navigationController =(UINavigationController *)self.window.rootViewController;
MainViewController *controller = (MainViewController *)navigationController.topViewController;

At that point, self.window.rootViewController is the OnboardingViewController, not a UINavigationController. Given that it isn't a UINavigationController, trying to access the topViewController property on it is causing it to crash.

You need to create your normal root view controller, not try to use the onboarding view controller.

mamaral commented 10 years ago

I'm closing this for now, as it appears to be an implementation issue and not a bug.

pavkosykh commented 10 years ago

Thanks Mike.)) good luck)