与登录视图控制器作为根SplitViewController(SplitViewController

2019-08-16 19:18发布

所以,我一直在研究如何使一个登录视图控制器作为初始视图控制器,而不是SPLITVIEW。

一些我见过会推荐一个模态视图的答案被加载? 我不知道该如何设置。

例如。

如何将UISplitViewController的iPad之前添加一个登录视图

如何实现对二级SplitViewController?

所以我添加那些对loginviewcontroller类? 还是在哪里?

任何意见是值得欢迎的。

谢谢!!

Answer 1:

一个与(全屏)登录和一个与拆分视图:我创建了两个故事板做到了这一点。

在它们之间进行切换,我添加了一个自定义的协议:

#import <Foundation/Foundation.h>

@protocol RootViewControllerDelegate <NSObject>

-(void)switchToStoryboard: (UIStoryboard *) storyboad animationDirectionOrNil: (NSString *)direction;

@end

所述的AppDelegate然后实现此协议:

-(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"];
    }
}

正如你所看到的,它试图将自身重新设置为代表,所以其他视图 - 控制器可以切换回或其他情节串连图板。 为了使这一工作,你就必须继承UISplitView:

#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

这个简单的实现查找孩子 - 视图 - 控制器,接受根 - 视图 - 控制器的委托和手下来。 所以,当你想要一个“显示登录”按钮上增加一定的(主-或detail-)认为,刚刚创建自己的UIViewController子类,添加一个@property id<RootViewControllerDelegate> rootViewControllerDelegate和相关联的动作像这样用按钮:

- (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];
}

随意调整一切以您的需求。



Answer 2:

好这里是我的朋友。 我在BTN创造了一个IBAction为与故事板的模式选项推新视图。 他们我插在班登录视图也指保持记录海峡常数。 然后登录后认识我推的新视图。 裸记住我是有这个用户创建他们的设备的密码,而不是从服务器导入它。 如果你想从服务器导入它,它会有所不同。

这里是日志中.H

#import <UIKit/UIKit.h>
#import "Constants.h"

@interface LogInViewController : UIViewController<UITextFieldDelegate>

@property (nonatomic) BOOL pinValidated;

@end

这里是登录.M代码

#import "LogInViewController.h"
#import "KeychainWrapper.h"

@interface LogInViewController ()

@end

@implementation LogInViewController

@synthesize pinValidated;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
    // Custom initialization
}
return self;
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

// Helper method to congregate the Name and PIN fields for validation.
- (BOOL)credentialsValidated 
{
NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
BOOL pin = [[NSUserDefaults standardUserDefaults] boolForKey:PIN_SAVED];
if (name && pin) {
    return YES;
} else {
    return NO;
}
}

- (void)presentAlertViewForPassword 
{

// 1
BOOL hasPin = [[NSUserDefaults standardUserDefaults] boolForKey:PIN_SAVED];

// 2
if (hasPin) {
    // 3
    NSString *user = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
    NSString *message = [NSString stringWithFormat:@"What is %@'s password?", user];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Enter Password" 
                                                    message:message  
                                                   delegate:self 
                                          cancelButtonTitle:@"Cancel" 
                                          otherButtonTitles:@"Done", nil];
    // 4
    [alert setAlertViewStyle:UIAlertViewStyleSecureTextInput]; // Gives us the password    field
    alert.tag = kAlertTypePIN;
    // 5
    UITextField *pinField = [alert textFieldAtIndex:0];
    pinField.delegate = self;
    pinField.autocapitalizationType = UITextAutocapitalizationTypeWords;
    pinField.tag = kTextFieldPIN;
    [alert show];
} else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Setup Credentials" 
                                                    message:@"Enter Your information!"  
                                                   delegate:self 
                                          cancelButtonTitle:@"Cancel" 
                                          otherButtonTitles:@"Done", nil];
    // 6
    [alert setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
    alert.tag = kAlertTypeSetup;
    UITextField *nameField = [alert textFieldAtIndex:0];
    nameField.autocapitalizationType = UITextAutocapitalizationTypeWords;
    nameField.placeholder = @"Name"; // Replace the standard placeholder text with   something more applicable
    nameField.delegate = self;
    nameField.tag = kTextFieldName;
    UITextField *passwordField = [alert textFieldAtIndex:1]; // Capture the Password text field since there are 2 fields
    passwordField.delegate = self;
    passwordField.tag = kTextFieldPassword;
    [alert show];
}
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 
{
if (alertView.tag == kAlertTypePIN) {
    if (buttonIndex == 1 && self.pinValidated) { // User selected "Done"
        [self performSegueWithIdentifier:@"ScoutSegue" sender:self];
        self.pinValidated = NO;
    } else { // User selected "Cancel"
        [self presentAlertViewForPassword];
    }
} else if (alertView.tag == kAlertTypeSetup) {
    if (buttonIndex == 1 && [self credentialsValidated]) { // User selected "Done"
        [self performSegueWithIdentifier:@"ScoutSegue" sender:self];
    } else { // User selected "Cancel"
        [self presentAlertViewForPassword];
    }
}
}


#pragma mark - Text Field + Alert View Methods
- (void)textFieldDidEndEditing:(UITextField *)textField 
{
// 1
switch (textField.tag) {
    case kTextFieldPIN: // We go here if this is the 2nd+ time used (we've already set a    PIN at Setup).
        NSLog(@"User entered PIN to validate");
        if ([textField.text length] > 0) {
            // 2
            NSUInteger fieldHash = [textField.text hash]; // Get the hash of the entered PIN, minimize contact with the real password
            // 3
            if ([KeychainWrapper compareKeychainValueForMatchingPIN:fieldHash]) { // Compare them
                NSLog(@"** User Authenticated!!");
                self.pinValidated = YES;
            } else {
                NSLog(@"** Wrong Password :(");
                self.pinValidated = NO;
            }
        }
        break;
    case kTextFieldName: // 1st part of the Setup flow.
        NSLog(@"User entered name");
        if ([textField.text length] > 0) {
            [[NSUserDefaults standardUserDefaults] setValue:textField.text  forKey:USERNAME];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
        break;
    case kTextFieldPassword: // 2nd half of the Setup flow.
        NSLog(@"User entered PIN");
        if ([textField.text length] > 0) {
            NSUInteger fieldHash = [textField.text hash];
            // 4
            NSString *fieldString = [KeychainWrapper securedSHA256DigestHashForPIN:fieldHash];
            NSLog(@"** Password Hash - %@", fieldString);
            // Save PIN hash to the keychain (NEVER store the direct PIN)
            if ([KeychainWrapper createKeychainValue:fieldString forIdentifier:PIN_SAVED])        {
                [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PIN_SAVED];
                [[NSUserDefaults standardUserDefaults] synchronize];
                NSLog(@"** Key saved successfully to Keychain!!");
            }                
        }
        break;
    default:
        break;
}
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
[super viewDidLoad];
self.pinValidated = NO;
}

- (void)viewDidAppear:(BOOL)animated 
{
[super viewDidAppear:animated];
[self presentAlertViewForPassword];
}

- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@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;

这里是keychainwrapper

#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 .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

这是用于创建之前的任何其它视图天气它是视图控制器或任何其他视图,如标签栏左右登录视图的蓝图。 采取在这组验证码良好的外观,并对其进行修改,请你。 希望这可以帮助你我的朋友。 代码都在那里,你所要做的就是研究并修改它们以你想要的。 快乐编码。



文章来源: SplitViewController with a Login View Controller as the root