Objective c 将登录视图控制器作为根的SplitViewController
所以我一直在研究如何将登录视图控制器作为初始视图控制器而不是splitview 我看到的一些答案建议加载模态视图?我不确定这是怎么设置的 例如 及 那么我要在loginviewcontroller类中添加这些吗?或者在哪里 欢迎任何建议Objective c 将登录视图控制器作为根的SplitViewController,objective-c,xcode,uisplitviewcontroller,uistoryboard,uistoryboardsegue,Objective C,Xcode,Uisplitviewcontroller,Uistoryboard,Uistoryboardsegue,所以我一直在研究如何将登录视图控制器作为初始视图控制器而不是splitview 我看到的一些答案建议加载模态视图?我不确定这是怎么设置的 例如 及 那么我要在loginviewcontroller类中添加这些吗?或者在哪里 欢迎任何建议 谢谢 这是我的朋友。我在btn中创建了一个iAction,并使用故事板的模态选项推送了新视图。我插入了login视图的类,该视图也引用了保持记录不变的常量。然后在登录被识别后,我推送了一个新视图。请记住,我是让用户在他们的设备中创建密码,而不是从服务器导入密
谢谢 这是我的朋友。我在btn中创建了一个iAction,并使用故事板的模态选项推送了新视图。我插入了login视图的类,该视图也引用了保持记录不变的常量。然后在登录被识别后,我推送了一个新视图。请记住,我是让用户在他们的设备中创建密码,而不是从服务器导入密码。如果要从服务器导入,则会有所不同 这是登录信息
#import <UIKit/UIKit.h>
#import "Constants.h"
@interface LogInViewController : UIViewController<UITextFieldDelegate>
@property (nonatomic) BOOL pinValidated;
@end
这是常数的代码
// Used for saving to NSUserDefaults that a PIN has been set, and is the unique identifier for the Keychain.
#define PIN_SAVED @"hasSavedPIN"
// Used for saving the user's name to NSUserDefaults.
#define USERNAME @"username"
// Used to specify the application used in accessing the Keychain.
#define APP_NAME [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]
// Used to help secure the PIN.
// Ideally, this is randomly generated, but to avoid the unnecessary complexity and overhead of storing the Salt separately, we will standardize on this key.
// !!KEEP IT A SECRET!!
#define SALT_HASH @"FvTivqTqZXsgLLx1v3P8TGRyVHaSOB1pvfm02wvGadj7RLHV8GrfxaZ84oGA8RsKdNRpxdAojXYg9iAj"
// Typedefs just to make it a little easier to read in code.
typedef enum {
kAlertTypePIN = 0,
kAlertTypeSetup
} AlertTypes;
typedef enum {
kTextFieldPIN = 1,
kTextFieldName,
kTextFieldPassword
} TextFieldTypes;
这是钥匙链包装器
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import <CommonCrypto/CommonHMAC.h>
@interface KeychainWrapper : NSObject
// Generic exposed method to search the keychain for a given value. Limit one result per search.
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier;
// Calls searchKeychainCopyMatchingIdentifier: and converts to a string value.
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier;
// Simple method to compare a passed in hash value with what is stored in the keychain.
// Optionally, we could adjust this method to take in the keychain key to look up the value.
+ (BOOL)compareKeychainValueForMatchingPIN:(NSUInteger)pinHash;
// Default initializer to store a value in the keychain.
// Associated properties are handled for you - setting Data Protection Access, Company Identifer (to uniquely identify string, etc).
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;
// Updates a value in the keychain. If you try to set the value with createKeychainValue: and it already exists,
// this method is called instead to update the value in place.
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;
// Delete a value in the keychain.
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier;
// Generates an SHA256 (much more secure than MD5) hash.
+ (NSString *)securedSHA256DigestHashForPIN:(NSUInteger)pinHash;
+ (NSString*)computeSHA256DigestForString:(NSString*)input;
@end
#导入
#进口
#进口
@接口KeychainWrapper:NSObject
//用于在密钥链中搜索给定值的通用公开方法。每次搜索限制一个结果。
+(NSData*)searchKeychainCopyMatchingIdentifier:(NSString*)标识符;
//调用searchKeychainCopyMatchingIdentifier:并转换为字符串值。
+(NSString*)keychainStringFromMatchingIdentifier:(NSString*)标识符;
//将传入的哈希值与存储在密钥链中的值进行比较的简单方法。
//或者,我们可以调整此方法以获取keychain键来查找值。
+(BOOL)compareKeychainValueForMatchingPIN:(nsInteger)pinHash;
//用于在键链中存储值的默认初始值设定项。
//为您处理相关属性-设置数据保护访问、公司标识(以唯一标识字符串等)。
+(BOOL)createKeychainValue:(NSString*)标识符的值:(NSString*)标识符;
//更新密钥链中的值。如果尝试使用createKeychainValue:设置该值,并且该值已存在,
//而是调用此方法以就地更新值。
+(BOOL)updateKeychainValue:(NSString*)标识符的值:(NSString*)标识符;
//删除键链中的值。
+(void)deleteItemFromKeychainWithIdentifier:(NSString*)标识符;
//生成SHA256(比MD5安全得多)散列。
+(NSString*)securedSHA256DigestHashForPIN:(NSInteger)pinHash;
+(NSString*)计算字符串的SA256DigestForString:(NSString*)输入;
@结束
最后是keychainwrapper.m的代码
#import "KeychainWrapper.h"
#import "Constants.h"
@implementation KeychainWrapper
// *** NOTE *** This class is ARC compliant - any references to CF classes must be paired with a "__bridge" statement to
// cast between Objective-C and Core Foundation Classes. WWDC 2011 Video "Introduction to Automatic Reference Counting" explains this.
// *** END NOTE ***
+ (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {
// Setup dictionary to access keychain.
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
// Specify we are using a password (rather than a certificate, internet password, etc).
[searchDictionary setObject:( id)kSecClassGenericPassword forKey:( id)kSecClass];
// Uniquely identify this keychain accessor.
[searchDictionary setObject:APP_NAME forKey:( id)kSecAttrService];
// Uniquely identify the account who will be accessing the keychain.
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:( id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:( id)kSecAttrAccount];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
// Limit search results to one.
[searchDictionary setObject:( id)kSecMatchLimitOne forKey:( id)kSecMatchLimit];
// Specify we want NSData/CFData returned.
[searchDictionary setObject:( id)kCFBooleanTrue forKey:( id)kSecReturnData];
// Search.
NSData *result = nil;
CFTypeRef foundDict = NULL;
OSStatus status = SecItemCopyMatching(( CFDictionaryRef)searchDictionary, &foundDict);
if (status == noErr) {
result = ( NSData *)foundDict;
} else {
result = nil;
}
return result;
}
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier
{
NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
if (valueData) {
NSString *value = [[NSString alloc] initWithData:valueData
encoding:NSUTF8StringEncoding];
return value;
} else {
return nil;
}
}
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{
NSMutableDictionary *dictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:valueData forKey:( id)kSecValueData];
// Protect the keychain entry so it's only valid when the device is unlocked.
[dictionary setObject:( id)kSecAttrAccessibleWhenUnlocked forKey:( id)kSecAttrAccessible];
// Add.
OSStatus status = SecItemAdd(( CFDictionaryRef)dictionary, NULL);
// If the addition was successful, return. Otherwise, attempt to update existing key or quit (return NO).
if (status == errSecSuccess) {
return YES;
} else if (status == errSecDuplicateItem){
return [self updateKeychainValue:value forIdentifier:identifier];
} else {
return NO;
}
}
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:( id)kSecValueData];
// Update.
OSStatus status = SecItemUpdate(( CFDictionaryRef)searchDictionary,
( CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
} else {
return NO;
}
}
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
CFDictionaryRef dictionary = ( CFDictionaryRef)searchDictionary;
//Delete.
SecItemDelete(dictionary);
}
+ (BOOL)compareKeychainValueForMatchingPIN:(NSUInteger)pinHash
{
if ([[self keychainStringFromMatchingIdentifier:PIN_SAVED] isEqualToString:[self securedSHA256DigestHashForPIN:pinHash]]) {
return YES;
} else {
return NO;
}
}
// This is where most of the magic happens (the rest of it happens in computeSHA256DigestForString: method below).
// Here we are passing in the hash of the PIN that the user entered so that we can avoid manually handling the PIN itself.
// Then we are extracting the username that the user supplied during setup, so that we can add another unique element to the hash.
// From there, we mash the user name, the passed-in PIN hash, and the secret key (from ChristmasConstants.h) together to create
// one long, unique string.
// Then we send that entire hash mashup into the SHA256 method below to create a "Digital Digest," which is considered
// a one-way encryption algorithm. "One-way" means that it can never be reverse-engineered, only brute-force attacked.
// The algorthim we are using is Hash = SHA256(Name + Salt + (Hash(PIN))). This is called "Digest Authentication."
+ (NSString *)securedSHA256DigestHashForPIN:(NSUInteger)pinHash
{
// 1
NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
name = [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 2
NSString *computedHashString = [NSString stringWithFormat:@"%@%i%@", name, pinHash, SALT_HASH];
// 3
NSString *finalHash = [self computeSHA256DigestForString:computedHashString];
NSLog(@"** Computed hash: %@ for SHA256 Digest: %@", computedHashString, finalHash);
return finalHash;
}
// This is where the rest of the magic happens.
// Here we are taking in our string hash, placing that inside of a C Char Array, then parsing it through the SHA256 encryption method.
+ (NSString*)computeSHA256DigestForString:(NSString*)input
{
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
// This is an iOS5-specific method.
// It takes in the data, how much data, and then output format, which in this case is an int array.
CC_SHA256(data.bytes, data.length, digest);
// Setup our Objective-C output.
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
// Parse through the CC_SHA256 results (stored inside of digest[]).
for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
@end
#导入“KeychainWrapper.h”
#导入“Constants.h”
@实现KeychainWrapper
//***注***该类符合ARC标准-对CF类的任何引用必须与“\uuu bridge”语句配对,以
/Objo C与核心基础类之间的转换。WWDC 2011视频“自动参考计数介绍”对此进行了解释。
//***结束说明***
+(NSMutableDictionary*)setupSearchDirectoryForIdentifier:(NSString*)标识符{
//设置字典以访问密钥链。
NSMutableDictionary*searchDictionary=[[NSMutableDictionary alloc]init];
//指定我们使用的是密码(而不是证书、internet密码等)。
[searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
//唯一标识此密钥链访问器。
[searchDictionary setObject:APP_NAME forKey:(id)kSecAttrService];
//唯一标识将访问密钥链的帐户。
NSData*encodedIdentifier=[标识符数据使用编码:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
返回搜索词典;
}
+(NSData*)searchKeychainCopyMatchingIdentifier:(NSString*)标识符
{
NSMutableDictionary*searchDictionary=[self-setupSearchDirectoryForIdentifier:identifier];
//将搜索结果限制为一个。
[searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
//指定要返回的NSData/CFData。
[searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
//搜索。
NSData*结果=零;
CFTypeRef foundDict=NULL;
OSStatus status=SecItemCopyMatching((CFDictionaryRef)searchDictionary和foundDict);
如果(状态==noErr){
结果=(NSData*)foundDict;
}否则{
结果=零;
}
返回结果;
}
+(NSString*)keychainStringFromMatchingIdentifier:(NSString*)标识符
{
NSData*valueData=[self-searchKeychainCopyMatchingIdentifier:identifier];
if(值数据){
NSString*value=[[NSString alloc]initWithData:valueData
编码:NSUTF8StringEncoding];
返回值;
}否则{
返回零;
}
}
+(BOOL)createKeychainValue:(NSString*)标识符的值:(NSString*)标识符
{
NSMutableDictionary*dictionary=[self-setupSearchDirectoryForIdentifier:identifier];
NSData*valueData=[value dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:valueData forKey:(id)kSecValueData];
//保护钥匙链条目,使其仅在设备解锁时有效。
[dictionary setObject:(id)ksecattraccessibleewhen unlocked forKey:(id)kSecAttrAccessible];
//加上。
OSStatus status=SecItemAdd((CFDictionaryRef)dictionary,NULL);
//如果添加成功,则返回。否则,尝试更新现有密钥或退出(返回否)。
如果(状态==errSecSuccess){
返回YES;
}else if(状态==errSecDuplicateItem){
返回[self-updateKeychainValue:value forIdentifier:identifier];
}否则{
返回否;
}
}
+(BOOL)updateKeychainValue:(NSString*)标识符的值:(NSString*)标识符
{
NSMutableDictionary*searchDictionary=[self-setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary*updateDictionary=[[NSMutableDictionary alloc]init];
NSData*valueData=[value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:(id)kSecValueData];
//更新。
骨状态
#import "KeychainWrapper.h"
#import "Constants.h"
@implementation KeychainWrapper
// *** NOTE *** This class is ARC compliant - any references to CF classes must be paired with a "__bridge" statement to
// cast between Objective-C and Core Foundation Classes. WWDC 2011 Video "Introduction to Automatic Reference Counting" explains this.
// *** END NOTE ***
+ (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {
// Setup dictionary to access keychain.
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
// Specify we are using a password (rather than a certificate, internet password, etc).
[searchDictionary setObject:( id)kSecClassGenericPassword forKey:( id)kSecClass];
// Uniquely identify this keychain accessor.
[searchDictionary setObject:APP_NAME forKey:( id)kSecAttrService];
// Uniquely identify the account who will be accessing the keychain.
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:( id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:( id)kSecAttrAccount];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
// Limit search results to one.
[searchDictionary setObject:( id)kSecMatchLimitOne forKey:( id)kSecMatchLimit];
// Specify we want NSData/CFData returned.
[searchDictionary setObject:( id)kCFBooleanTrue forKey:( id)kSecReturnData];
// Search.
NSData *result = nil;
CFTypeRef foundDict = NULL;
OSStatus status = SecItemCopyMatching(( CFDictionaryRef)searchDictionary, &foundDict);
if (status == noErr) {
result = ( NSData *)foundDict;
} else {
result = nil;
}
return result;
}
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier
{
NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
if (valueData) {
NSString *value = [[NSString alloc] initWithData:valueData
encoding:NSUTF8StringEncoding];
return value;
} else {
return nil;
}
}
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{
NSMutableDictionary *dictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:valueData forKey:( id)kSecValueData];
// Protect the keychain entry so it's only valid when the device is unlocked.
[dictionary setObject:( id)kSecAttrAccessibleWhenUnlocked forKey:( id)kSecAttrAccessible];
// Add.
OSStatus status = SecItemAdd(( CFDictionaryRef)dictionary, NULL);
// If the addition was successful, return. Otherwise, attempt to update existing key or quit (return NO).
if (status == errSecSuccess) {
return YES;
} else if (status == errSecDuplicateItem){
return [self updateKeychainValue:value forIdentifier:identifier];
} else {
return NO;
}
}
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:( id)kSecValueData];
// Update.
OSStatus status = SecItemUpdate(( CFDictionaryRef)searchDictionary,
( CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
} else {
return NO;
}
}
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
CFDictionaryRef dictionary = ( CFDictionaryRef)searchDictionary;
//Delete.
SecItemDelete(dictionary);
}
+ (BOOL)compareKeychainValueForMatchingPIN:(NSUInteger)pinHash
{
if ([[self keychainStringFromMatchingIdentifier:PIN_SAVED] isEqualToString:[self securedSHA256DigestHashForPIN:pinHash]]) {
return YES;
} else {
return NO;
}
}
// This is where most of the magic happens (the rest of it happens in computeSHA256DigestForString: method below).
// Here we are passing in the hash of the PIN that the user entered so that we can avoid manually handling the PIN itself.
// Then we are extracting the username that the user supplied during setup, so that we can add another unique element to the hash.
// From there, we mash the user name, the passed-in PIN hash, and the secret key (from ChristmasConstants.h) together to create
// one long, unique string.
// Then we send that entire hash mashup into the SHA256 method below to create a "Digital Digest," which is considered
// a one-way encryption algorithm. "One-way" means that it can never be reverse-engineered, only brute-force attacked.
// The algorthim we are using is Hash = SHA256(Name + Salt + (Hash(PIN))). This is called "Digest Authentication."
+ (NSString *)securedSHA256DigestHashForPIN:(NSUInteger)pinHash
{
// 1
NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
name = [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 2
NSString *computedHashString = [NSString stringWithFormat:@"%@%i%@", name, pinHash, SALT_HASH];
// 3
NSString *finalHash = [self computeSHA256DigestForString:computedHashString];
NSLog(@"** Computed hash: %@ for SHA256 Digest: %@", computedHashString, finalHash);
return finalHash;
}
// This is where the rest of the magic happens.
// Here we are taking in our string hash, placing that inside of a C Char Array, then parsing it through the SHA256 encryption method.
+ (NSString*)computeSHA256DigestForString:(NSString*)input
{
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
// This is an iOS5-specific method.
// It takes in the data, how much data, and then output format, which in this case is an int array.
CC_SHA256(data.bytes, data.length, digest);
// Setup our Objective-C output.
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
// Parse through the CC_SHA256 results (stored inside of digest[]).
for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
@end
#import <Foundation/Foundation.h>
@protocol RootViewControllerDelegate <NSObject>
-(void)switchToStoryboard: (UIStoryboard *) storyboad animationDirectionOrNil: (NSString *)direction;
@end
-(void)switchToStoryboard:(id)storyboad animationDirectionOrNil:(NSString *)direction {
UIViewController *newRoot=[storyboad instantiateInitialViewController];
if ([newRoot respondsToSelector:@selector(setRootViewControllerDelegate:)]) {
[newRoot setRootViewControllerDelegate:self];
}
self.window.rootViewController=newRoot;
if(direction){
CATransition* transition=[CATransition animation];
transition.type=kCATransitionPush;
transition.subtype=direction;
[self.window.layer addAnimation:transition forKey:@"push_transition"];
}
}
#import <UIKit/UIKit.h>
#import "RootViewControllerDelegate.h"
@interface MySplitViewController : UISplitViewController
@property (nonatomic, weak) id <RootViewControllerDelegate> rootViewControllerDelegate;
@end
#import "MySplitViewController.h"
@implementation MySplitViewController
@synthesize rootViewControllerDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
for (UIViewController *viewController in self.viewControllers) {
if ([viewController respondsToSelector:@selector(setRootViewControllerDelegate:)]) {
[viewController setRootViewControllerDelegate:self.rootViewControllerDelegate];
}
}
}
@end
- (IBAction)loginButtonClicked:(id)sender {
UIStoryboard *mainSB=[UIStoryboard storyboardWithName:@"LoginStoryboard" bundle:nil];
NSString *animationDirection=kCATransitionFromTop;
UIDeviceOrientation currentOrientation=[[UIDevice currentDevice] orientation];
if (currentOrientation==UIDeviceOrientationLandscapeLeft) {
animationDirection=kCATransitionFromBottom;
}
[self.rootViewControllerDelegate switchToStoryboard:mainSB animationDirectionOrNil:animationDirection];
}