Skip to content

Commit 152c9da

Browse files
committed
Added proper thread confinement
1 parent 0614fe7 commit 152c9da

File tree

4 files changed

+102
-32
lines changed

4 files changed

+102
-32
lines changed

TOPasscodeViewController/Models/TOPasscodeViewControllerAnimatedTransitioning.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
1717

1818
@property (nonatomic, weak, readonly) TOPasscodeViewController *passcodeViewController;
1919
@property (nonatomic, assign) BOOL dismissing;
20+
@property (nonatomic, assign) BOOL passcodeSuccess; //Play a different animation if the password succeeeded
2021

21-
- (instancetype)initWithPasscodeViewController:(TOPasscodeViewController *)passcodeViewController dismissing:(BOOL)dismissing;
22+
- (instancetype)initWithPasscodeViewController:(TOPasscodeViewController *)passcodeViewController dismissing:(BOOL)dismissing success:(BOOL)success;
2223

2324
@end
2425

TOPasscodeViewController/Models/TOPasscodeViewControllerAnimatedTransitioning.m

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,20 @@ @interface TOPasscodeViewControllerAnimatedTransitioning ()
1616

1717
@implementation TOPasscodeViewControllerAnimatedTransitioning
1818

19-
- (instancetype)initWithPasscodeViewController:(TOPasscodeViewController *)passcodeViewController dismissing:(BOOL)dismissing
19+
- (instancetype)initWithPasscodeViewController:(TOPasscodeViewController *)passcodeViewController dismissing:(BOOL)dismissing success:(BOOL)success
2020
{
2121
if (self = [super init]) {
2222
_passcodeViewController = passcodeViewController;
2323
_dismissing = dismissing;
24+
_passcodeSuccess = success;
2425
}
2526

2627
return self;
2728
}
2829

2930
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext
3031
{
31-
return 0.5f;
32+
return 0.35f;
3233
}
3334

3435
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
@@ -85,6 +86,13 @@ - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionC
8586
[transitionContext completeTransition:completed];
8687
};
8788

89+
if (self.passcodeSuccess && self.dismissing) {
90+
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
91+
animation.duration = [self transitionDuration:transitionContext];
92+
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.75f, 0.75f, 1)];
93+
[passcodeView.layer addAnimation:animation forKey:@"transform"];
94+
}
95+
8896
[UIView animateWithDuration:[self transitionDuration:transitionContext]
8997
delay:0.0f
9098
// usingSpringWithDamping:1.0f

TOPasscodeViewController/TOPasscodeViewController.m

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ @interface TOPasscodeViewController () <UIViewControllerTransitioningDelegate>
1717
/* State */
1818
@property (nonatomic, assign, readwrite) TOPasscodeType passcodeType;
1919
@property (nonatomic, assign) CGFloat keyboardHeight;
20+
@property (nonatomic, assign) BOOL passcodeSuccess;
21+
@property (nonatomic, readonly) UIView *leftButton;
22+
@property (nonatomic, readonly) UIView *rightButton;
2023

2124
/* Views */
2225
@property (nonatomic, strong, readwrite) UIVisualEffectView *backgroundEffectView;
@@ -25,6 +28,7 @@ @interface TOPasscodeViewController () <UIViewControllerTransitioningDelegate>
2528
@property (nonatomic, strong, readwrite) UIButton *biometricButton;
2629
@property (nonatomic, strong, readwrite) UIButton *cancelButton;
2730

31+
2832
@end
2933

3034
@implementation TOPasscodeViewController
@@ -323,18 +327,16 @@ - (void)verticalLayoutAccessoryButtonsForSize:(CGSize)size
323327
CGFloat inset = self.passcodeView.keypadButtonInset;
324328
CGPoint point = (CGPoint){0.0f, (self.view.bounds.size.height - self.keyboardHeight) - verticalInset};
325329

326-
UIButton *leftButton = self.leftAccessoryButton ? self.leftAccessoryButton : self.biometricButton;
327-
if (leftButton) {
328-
[leftButton sizeToFit];
330+
if (self.leftButton) {
331+
[self.leftButton sizeToFit];
329332
point.x = self.passcodeView.frame.origin.x + inset;
330-
leftButton.center = point;
333+
self.leftButton.center = point;
331334
}
332335

333-
UIButton *rightButton = self.rightAccessoryButton ? self.rightAccessoryButton : self.cancelButton;
334-
if (rightButton) {
335-
[rightButton sizeToFit];
336+
if (self.rightButton) {
337+
[self.rightButton sizeToFit];
336338
point.x = CGRectGetMaxX(self.passcodeView.frame) - inset;
337-
rightButton.center = point;
339+
self.rightButton.center = point;
338340
}
339341
}
340342

@@ -351,27 +353,24 @@ - (void)horizontalLayoutAccessoryButtonsForSize:(CGSize)size
351353
verticalInset = 35.0f;
352354
}
353355

354-
355-
UIButton *leftButton = self.leftAccessoryButton ? self.leftAccessoryButton : self.biometricButton;
356-
if (leftButton) {
357-
[leftButton sizeToFit];
358-
CGRect frame = leftButton.frame;
356+
if (self.leftButton) {
357+
[self.leftButton sizeToFit];
358+
CGRect frame = self.leftButton.frame;
359359
frame.origin.y = (self.view.bounds.size.height - verticalInset) - (frame.size.height * 0.5f);
360360
frame.origin.x = (CGRectGetMaxX(passcodeViewFrame) - buttonInset) - (frame.size.width * 0.5f);
361-
leftButton.frame = CGRectIntegral(frame);
361+
self.leftButton.frame = CGRectIntegral(frame);
362362
}
363363

364-
UIButton *rightButton = self.rightAccessoryButton ? self.rightAccessoryButton : self.cancelButton;
365-
if (rightButton) {
366-
[rightButton sizeToFit];
367-
CGRect frame = rightButton.frame;
364+
if (self.rightButton) {
365+
[self.rightButton sizeToFit];
366+
CGRect frame = self.rightButton.frame;
368367
frame.origin.y = verticalInset - (frame.size.height * 0.5f);
369368
frame.origin.x = (CGRectGetMaxX(passcodeViewFrame) - buttonInset) - (frame.size.width * 0.5f);
370-
rightButton.frame = CGRectIntegral(frame);
369+
self.rightButton.frame = CGRectIntegral(frame);
371370
}
372371

373-
[self.view bringSubviewToFront:rightButton];
374-
[self.view bringSubviewToFront:leftButton];
372+
[self.view bringSubviewToFront:self.rightButton];
373+
[self.view bringSubviewToFront:self.leftButton];
375374
}
376375

377376
- (void)layoutAccessoryButtonsForSize:(CGSize)size
@@ -430,6 +429,9 @@ - (void)didCompleteEnteringPasscode:(NSString *)passcode
430429
return;
431430
}
432431

432+
// Hang onto the fact the passcode was successful to play a nicer dismissal animation
433+
self.passcodeSuccess = YES;
434+
433435
// Perform handler if correctly entered
434436
if ([self.delegate respondsToSelector:@selector(didInputCorrectPasscodeInPasscodeViewController:)]) {
435437
[self.delegate didInputCorrectPasscodeInPasscodeViewController:self];
@@ -471,12 +473,23 @@ - (void)keyboardWillChangeFrame:(NSNotification *)notification
471473
presentingController:(UIViewController *)presenting
472474
sourceController:(UIViewController *)source
473475
{
474-
return [[TOPasscodeViewControllerAnimatedTransitioning alloc] initWithPasscodeViewController:self dismissing:NO];
476+
return [[TOPasscodeViewControllerAnimatedTransitioning alloc] initWithPasscodeViewController:self dismissing:NO success:NO];
475477
}
476478

477479
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
478480
{
479-
return [[TOPasscodeViewControllerAnimatedTransitioning alloc] initWithPasscodeViewController:self dismissing:YES];
481+
return [[TOPasscodeViewControllerAnimatedTransitioning alloc] initWithPasscodeViewController:self dismissing:YES success:self.passcodeSuccess];
482+
}
483+
484+
#pragma mark - Convenience Accessors -
485+
- (UIView *)leftButton
486+
{
487+
return self.leftAccessoryButton ? self.leftAccessoryButton : self.biometricButton;
488+
}
489+
490+
- (UIView *)rightButton
491+
{
492+
return self.rightAccessoryButton ? self.rightAccessoryButton : self.cancelButton;
480493
}
481494

482495
#pragma mark - Public Accessors -
@@ -571,4 +584,43 @@ - (void)setAccessoryButtonTintColor:(UIColor *)accessoryButtonTintColor
571584
[self applyThemeForStyle:self.style];
572585
}
573586

587+
- (void)setContentHidden:(BOOL)contentHidden
588+
{
589+
[self setContentHidden:contentHidden animated:NO];
590+
}
591+
592+
- (void)setContentHidden:(BOOL)hidden animated:(BOOL)animated
593+
{
594+
if (hidden == _contentHidden) { return; }
595+
_contentHidden = hidden;
596+
597+
void (^setViewsHiddenBlock)(BOOL) = ^(BOOL hidden) {
598+
self.passcodeView.hidden = hidden;
599+
self.leftButton.hidden = hidden;
600+
self.rightButton.hidden = hidden;
601+
};
602+
603+
void (^completionBlock)(BOOL) = ^(BOOL complete) {
604+
setViewsHiddenBlock(hidden);
605+
};
606+
607+
if (!animated) {
608+
completionBlock(YES);
609+
return;
610+
}
611+
612+
// Make sure the views are visible before the animation
613+
setViewsHiddenBlock(NO);
614+
615+
void (^animationBlock)() = ^{
616+
CGFloat alpha = hidden ? 0.0f : 1.0f;
617+
self.passcodeView.contentAlpha = alpha;
618+
self.leftButton.alpha = alpha;
619+
self.rightButton.alpha = alpha;
620+
};
621+
622+
// Animate
623+
[UIView animateWithDuration:0.4f animations:animationBlock completion:completionBlock];
624+
}
625+
574626
@end

TOPasscodeViewControllerExample/ViewController.m

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,22 @@ - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscode
9494
// Touch ID validation was successful
9595
// (Use this to dismiss the passcode controller and display the protected content)
9696
if (success) {
97-
// Create a new Touch ID context for next time
98-
[weakSelf.authContext invalidate];
99-
weakSelf.authContext = [[LAContext alloc] init];
100-
101-
// Dismiss the passcode controller
102-
[weakSelf dismissViewControllerAnimated:YES completion:nil];
97+
dispatch_async(dispatch_get_main_queue(), ^{
98+
// Create a new Touch ID context for next time
99+
[weakSelf.authContext invalidate];
100+
weakSelf.authContext = [[LAContext alloc] init];
101+
102+
// Dismiss the passcode controller
103+
[weakSelf dismissViewControllerAnimated:YES completion:nil];
104+
});
103105
return;
104106
}
105107

108+
// Actual UI changes need to be made on the main queue
109+
dispatch_async(dispatch_get_main_queue(), ^{
110+
[passcodeViewController setContentHidden:NO animated:YES];
111+
});
112+
106113
// The user hit 'Enter Password'. This should probably do nothing
107114
// but make sure the passcode controller is visible.
108115
if (error.code == kLAErrorUserFallback) {
@@ -122,6 +129,8 @@ - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscode
122129
NSLog(@"%@", error.localizedDescription);
123130
};
124131

132+
[passcodeViewController setContentHidden:YES animated:YES];
133+
125134
[self.authContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:reply];
126135
}
127136

0 commit comments

Comments
 (0)