Skip to content

Commit

Permalink
Fixed a retain cycle
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelomer committed Feb 16, 2020
1 parent 9068065 commit f56680e
Show file tree
Hide file tree
Showing 11 changed files with 371 additions and 261 deletions.
1 change: 0 additions & 1 deletion Goose/MGContainerView.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

@interface MGContainerView : UIView {
UIVisualEffectView *_visualEffect;
UITapGestureRecognizer *_gestureRecognizer;
}
@property (nonatomic, readonly, strong) UIView *contentView;
+ (UIBlurEffectStyle)blurStyle;
Expand Down
7 changes: 3 additions & 4 deletions Goose/MGContainerView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,16 @@ - (instancetype)initWithFrame:(CGRect)frame {
if (!_contentView) return nil;
[self addSubview:_visualEffect];
[self addSubview:_contentView];
_gestureRecognizer = [[UITapGestureRecognizer alloc]
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleTap:)
];
[self addGestureRecognizer:_gestureRecognizer];
[self addGestureRecognizer:gestureRecognizer];
}
return self;
}

- (void)handleTap:(UITapGestureRecognizer *)sender
{
- (void)handleTap:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
[UIView
animateWithDuration:0.5
Expand Down
15 changes: 15 additions & 0 deletions Goose/MGGooseController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import <UIKit/UIKit.h>

@class MGGooseView;
@class MGContainerView;

@interface MGGooseController : NSObject {
NSPointerArray *containers;
NSInteger frameHandlerIndex;
BOOL getMemeFromTheLeft;
__kindof MGContainerView *imageContainer;
}
@property (nonatomic, strong, readonly) MGGooseView *gooseView;
- (instancetype)initWithGoose:(MGGooseView *)goose;
- (void)startLooping;
@end
260 changes: 260 additions & 0 deletions Goose/MGGooseController.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
#import "MGGooseController.h"
#import "MGGooseView.h"
#import "MGTextContainerView.h"
#import "MGImageContainerView.h"
#import "MGViewController.h"
#import "MGGooseController.h"
#import "NSPointerArray+FixedCompact.h"

#pragma GCC diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"

@implementation MGGooseController

static const CGFloat defaultSpeed = 2.6;

- (void)loadMeme {
BOOL isImage = [imageContainer isKindOfClass:[MGImageContainerView class]];
NSString *path = [NSString
stringWithFormat:@"/Library/Application Support/MobileGoose/%@",
isImage ? @"Memes" : @"Notes"
];
NSArray *files = [NSFileManager.defaultManager contentsOfDirectoryAtPath:path error:nil];
if ([(((NSNumber *)PrefValue(@"DisableDefaultGifts")) ?: @NO) boolValue]) {
NSMutableArray *mFiles = files.mutableCopy;
[mFiles removeObject:@"DefaultMeme.png"];
[mFiles removeObject:@"DefaultNote.txt"];
files = mFiles.copy;
}
NSString *randomFile = files.count ? [path stringByAppendingPathComponent:files[arc4random_uniform(files.count)]] : nil;
if (isImage) {
UIImage *image = nil;
if (randomFile) {
image = [UIImage imageWithContentsOfFile:randomFile];
}
dispatch_async(dispatch_get_main_queue(), ^{
__kindof UIImageView *imageView = [(MGImageContainerView *)imageContainer imageView];
imageView.image = image;
[imageView setNeedsDisplay];
});
}
else {
NSString *text = nil;
if (files.count) {
__unused NSStringEncoding encoding;
text = [NSString
stringWithContentsOfFile:randomFile
usedEncoding:&encoding
error:nil
];
}
dispatch_async(dispatch_get_main_queue(), ^{
[(MGTextContainerView *)imageContainer textLabel].text = text ?: @"Could not load note";
if (!text) {
[(MGTextContainerView *)imageContainer textLabel].font = [UIFont boldSystemFontOfSize:[(MGTextContainerView *)imageContainer textLabel].font.pointSize];
}
});
}
}

- (void)crazyModeCompletionTurnCompletion {
[_gooseView walkForDuration:-1 speed:defaultSpeed completionHandler:nil];
frameHandlerIndex = [_gooseView addFrameHandlerWithTarget:self action:@selector(getBackToNormalFrameHandlerForSender:state:)];
}

- (void)memeAnimationCompletion {
[_gooseView removeFrameHandlerAtIndex:frameHandlerIndex];
_gooseView.stopsAtEdge = YES;
imageContainer = nil;
[self turnToUserAnimation];
}

- (void)crazyModeCompletion {
[_gooseView removeFrameHandlerAtIndex:frameHandlerIndex];
if (![_gooseView isFrameAtEdge:_gooseView.frame]) {
_gooseView.stopsAtEdge = YES;
[self turnToUserAnimation];
}
else {
[_gooseView setFacingTo:45.0 animationCompletion:^(id sender){
[self crazyModeCompletionTurnCompletion];
}];
}
}

- (void)handleCrazyModeFrameForSender:(MGGooseView *)sender state:(MGGooseFrameState)state {
if (state == MGGooseDidFinishDrawing) {
sender.facingTo += ((CGFloat)arc4random_uniform(150) / 10.0) - 7.5;
}
}

- (void)handleCrazyModePreparationFrameForSender:(MGGooseView *)sender state:(MGGooseFrameState)state {
if (state == MGGooseDidFinishDrawing) {
if (sender.positionChange.x <= -10) {
[sender removeFrameHandlerAtIndex:frameHandlerIndex];
[sender
walkForDuration:((CGFloat)arc4random_uniform(30) / 10.0)+6.0
speed:defaultSpeed*3.0
completionHandler:^(MGGooseView *sender){ [self crazyModeCompletion]; }
];
frameHandlerIndex = [sender addFrameHandlerWithTarget:self action:@selector(handleCrazyModeFrameForSender:state:)];
}
}
}

- (void)prepareForGoingCrazy {
_gooseView.stopsAtEdge = NO;
[_gooseView walkForDuration:-1.0 speed:defaultSpeed completionHandler:nil];
frameHandlerIndex = [_gooseView
addFrameHandlerWithTarget:self
action:@selector(handleCrazyModePreparationFrameForSender:state:)
];
}

- (void)pullMemeFrameForSender:(MGGooseView *)sender state:(MGGooseFrameState)state {
if (state == MGGooseDidFinishDrawing) {
CGPoint center = imageContainer.center;
center.x += sender.positionChange.x;
imageContainer.center = center;
}
}

- (void)continueWithRandomAnimation {
NSLog(@"%lu", (unsigned long)containers.count);
uint8_t randomValue = arc4random_uniform(50);
[containers MGCompact];
if ((containers.count >= 5) && (randomValue >= 40)) randomValue += 10;
Class cls = nil;
if ([(((NSNumber *)PrefValue(@"BringImages")) ?: @YES) boolValue] &&
(randomValue <= 44) && (randomValue >= 40))
{
// 10% chance
cls = [MGImageContainerView class];
}
else if ((randomValue >= 30) && (randomValue < 33)) {
// 6% chance
[_gooseView setFacingTo:0.0 animationCompletion:^(id sender){
[self prepareForGoingCrazy];
}];
return;
}
else if ([(((NSNumber *)PrefValue(@"BringNotes")) ?: @NO) boolValue] &&
(randomValue <= 49) && (randomValue >= 45))
{
// 10% chance
cls = [MGTextContainerView class];
}
else {
[self turnToRandomAngle];
return;
}
imageContainer = [[cls alloc] initWithFrame:CGRectMake(0,0,125,125)];
[containers addPointer:(__bridge void *)imageContainer];
imageContainer.transform = MGGetTransform();
imageContainer.hidden = YES;
[containers MGCompact];
[_gooseView._viewControllerForAncestor.view addSubview:imageContainer];
imageContainer.layer.zPosition = containers.count;
getMemeFromTheLeft = arc4random_uniform(2);
[_gooseView setFacingTo:(!!getMemeFromTheLeft * 180.0) animationCompletion:^(id sender){
[self turnToMemeAnimation];
}];
}

- (void)gotoMemeFrameHandlerForSender:(MGGooseView *)sender state:(MGGooseFrameState)state {
if (state == MGGooseDidFinishDrawing) {
if ((getMemeFromTheLeft) ?
(sender.frame.origin.x <= -15.0) :
(sender.frame.origin.x >= (_gooseView._viewControllerForAncestor.view.frame.size.width - sender.frame.size.width + 26.0)))
{
[sender removeFrameHandlerAtIndex:frameHandlerIndex];
frameHandlerIndex = [sender addFrameHandlerWithTarget:self action:@selector(pullMemeFrameForSender:state:)];
CGPoint point = CGPointMake(-(imageContainer.frame.size.width/2.0), sender.center.y);
CGFloat min = (imageContainer.frame.size.height / 2.0);
CGFloat max = (sender._viewControllerForAncestor.view.frame.size.height - min);
point.y += (((CGFloat)arc4random_uniform(100) / 10.0) - 7.5);
if (point.y < min) point.y = min;
else if (point.y > max) point.y = max;
if (!getMemeFromTheLeft) point.x += (imageContainer.frame.size.width + sender._viewControllerForAncestor.view.frame.size.width);
imageContainer.center = point;
imageContainer.hidden = NO;
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^{ [self loadMeme]; }
);
[sender walkForDuration:(3.0 + ((NSTimeInterval)arc4random_uniform(15) / 10.0)) speed:-2.0 completionHandler:^(id sender){
[self memeAnimationCompletion];
}];
}
}
}

- (void)turnToMemeAnimation {
frameHandlerIndex = [_gooseView addFrameHandlerWithTarget:self action:@selector(gotoMemeFrameHandlerForSender:state:)];
_gooseView.stopsAtEdge = NO;
[_gooseView walkForDuration:-1 speed:4.8 completionHandler:nil];
}

- (void)turnToUserAnimation {
CGRect bounds = _gooseView._viewControllerForAncestor.view.bounds;
CGFloat to = 45.0;
if (_gooseView.center.x > (bounds.size.width/2)) to = 180-to;
[_gooseView setFacingTo:to animationCompletion:^(id sender){
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * ((double)arc4random_uniform(50) / 10.0)),
dispatch_get_main_queue(),
^{ [self continueWithRandomAnimation]; }
);
}];
}

- (void)turnToRandomAngle {
CGRect frame;
CGFloat degrees = (CGFloat)arc4random_uniform(360);
do {
// Check if
frame = _gooseView.frame;
degrees += 10.0;
frame.origin.x += cos(DEG_TO_RAD(degrees)) * defaultSpeed * 5.0;
frame.origin.y += sin(DEG_TO_RAD(degrees)) * defaultSpeed * 5.0;
} while ([_gooseView isFrameAtEdge:frame]);
[_gooseView
setFacingTo:degrees
animationCompletion:^(id sender){ [self defaultWalkAnimation]; }
];
}

- (void)defaultWalkAnimation {
[_gooseView
walkForDuration:(NSTimeInterval)(arc4random_uniform(3)+1)
speed:defaultSpeed
completionHandler:^(id sender){ [self turnToUserAnimation]; }
];
}

- (instancetype)initWithGoose:(MGGooseView *)goose {
if ((self = [super init])) {
_gooseView = goose;
containers = [NSPointerArray weakObjectsPointerArray];
}
return self;
}

- (void)startLooping {
[self defaultWalkAnimation];
}

- (void)getBackToNormalFrameHandlerForSender:(MGGooseView *)sender state:(MGGooseFrameState)state {
if (state == MGGooseDidFinishDrawing) {
if (![sender isFrameAtEdge:sender.frame]) {
sender.stopsAtEdge = YES;
[sender stopWalking];
[sender removeFrameHandlerAtIndex:frameHandlerIndex];
[self turnToUserAnimation];
}
}
}

@end

#pragma GCC diagnostic pop
4 changes: 3 additions & 1 deletion Goose/MGGooseView.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef void(^MGGooseCommonBlock)(MGGooseView *);
MGGooseCommonBlock _walkCompletion;
MGGooseCommonBlock _animationCompletion;
CGFloat _walkMultiplier;
NSPointerArray *_frameHandlers;
NSMutableArray *_frameHandlers;
}
@property (nonatomic, strong) BOOL(^shouldRenderFrameBlock)(MGGooseView *);
@property (nonatomic, assign) CGFloat facingTo;
Expand All @@ -46,7 +46,9 @@ typedef void(^MGGooseCommonBlock)(MGGooseView *);
animationCompletion:(MGGooseCommonBlock)completion;
- (void)stopWalking;
- (NSUInteger)addFrameHandler:(MGGooseFrameHandler)handler;
- (NSUInteger)addFrameHandlerWithTarget:(id)target action:(SEL)action;
- (void)removeFrameHandlerAtIndex:(NSUInteger)index;
- (BOOL)isFrameAtEdge:(CGRect)frame;
+ (void)addSharedFrameHandler:(MGGooseFrameHandler)handler;
//+ (void)addSharedFrameHandlerWithTarget:(id)target action:(SEL)action;
@end
Loading

0 comments on commit f56680e

Please sign in to comment.