Search code examples
iosobjective-cuiviewappdelegatetouchesbegan

touchesBegan caught by AppDelegate instead of subclass of UIView


I was going through Chapter 5 of the iOS Programming by The Big Nerd Ranch Guide (4th edition, wanted Objective C), I followed the instructions on subclassing the UIView class and added the subview in AppDelegate, the thing is that the subview is not catching the touchesBegan event, but the AppDelegate is catching the signal.

didFinishLaunchingWithOptions method in AppDelegate:

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:[UIViewController alloc]];

CGRect firstFrame = self.window.bounds;

HypnosisView *firstView = [[HypnosisView alloc] initWithFrame:firstFrame];
[self.window addSubview:firstView];
[firstView becomeFirstResponder];

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];

return YES;

The two initialization methods for HypnosisView, subclass of UIView are defined as follows:

#import "HypnosisView.h"

@interface HypnosisView ()

@property (strong, nonatomic) UIColor *circleColor;

@end

@implementation HypnosisView

// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    CGRect bounds = self.bounds;
    CGRect frame = self.frame;

    // Figure out the center of the bounds rectangle
    CGPoint center;
     center.x = frame.origin.x + frame.size.width / 2.0;
    center.y = frame.origin.y + frame.size.height / 2.0;

    // The largest circle will circumscribe the view
    float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;

     UIBezierPath *path = [[UIBezierPath alloc] init];

    for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
        [path moveToPoint:CGPointMake(center.x + currentRadius, center.y)];

        [path addArcWithCenter:center
                    radius:currentRadius
                startAngle:0.0
                  endAngle:M_PI * 2
                 clockwise:YES];
    }

    // Configure line with to 10 points
    path.lineWidth = 10;

    // Configure the drawing color to light gray
    [self.circleColor setStroke];

    // Draw the line!
    [path stroke];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // All HypnosisViews start with a clear background color
        self.backgroundColor = [UIColor clearColor];
        self.circleColor = [UIColor lightGrayColor];

        self.userInteractionEnabled = YES;
    }
    return self;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"%@ was touched", self);
}

Solution

  • In your Appdelegate.m, you should makeKeyAndVisible your window firstly, makeKeyAndVisible will set the window to keyWindow, and will bring the window to the front of all of your windows.

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        [self.window setRootViewController:[UIViewController alloc]];
    
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
    
        CGRect firstFrame = self.window.bounds;
    
        HypnosisView *firstView = [[HypnosisView alloc] initWithFrame:firstFrame];
        [self.window addSubview:firstView];
        [firstView becomeFirstResponder];
    
    
    
        return YES;
    }