Home > database >  External Display Crashing On Adding Subview
External Display Crashing On Adding Subview

Time:08-04

In my app, there is one small section that displays lyrics to songs (PDFs loaded in a WKWebView). What I want to be able to do, is when you mirror that screen to an Apple TV, still control it with the iPhone/iPad, but have it be the full screen, optimized for a TV display. I have the following code set up in the Class for viewing the songs, but it keeps crashing with autoLayoutConstraint errors when I try loading it. Anyone have an idea what's going on?

Songs.h:
@interface Songs : UIViewController <UIGestureRecognizerDelegate>{
    IBOutlet WKWebView *savedweb;
    NSString *selectedCountry;
    IBOutlet UIActivityIndicatorView *activity;
    NSTimer *timer;
}

@property (nonatomic, retain) NSString *selectedSong;
@property (nonatomic, retain) UIActivityIndicatorView *activity;
@property (nonatomic, retain) UIWindow *secondWindow;
@end

Songs.m

- (void)viewDidLoad {
    if ([UIScreen screens].count > 1) {
        [self setUpSecondWindowForScreen:[UIScreen screens][1]];
      }

      NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
      [center addObserver:self selector:@selector(handleScreenDidConnectNotification:)
                     name:UIScreenDidConnectNotification object:nil];
      [center addObserver:self selector:@selector(handleScreenDidDisconnectNotification:)
                     name:UIScreenDidDisconnectNotification object:nil];
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
       NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:selectedSong] stringByAppendingString:@".pdf"];
   
        NSURL *url = [NSURL fileURLWithPath:pdfPath];
        NSLog(@"%@",url);
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [savedweb loadRequest:request];
        UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleNavBar:)];
        [self.view addGestureRecognizer:gesture];
        gesture.delegate = self;
        [gesture release];
        timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:@selector(tick) userInfo:nil repeats:YES];
        
    
   
}
- (void)handleScreenDidConnectNotification:(NSNotification*)notification {
  if (!self.secondWindow) {
    [self setUpSecondWindowForScreen:[notification object]];
  }
}

- (void)handleScreenDidDisconnectNotification:(NSNotification*)notification {
  if (self.secondWindow) {
    self.secondWindow = nil;
  }
}
- (void)setUpSecondWindowForScreen:(UIScreen*)screen {
  self.secondWindow = [[UIWindow alloc] init];
  self.secondWindow.screen = screen;
  self.secondWindow.screen.overscanCompensation = UIScreenOverscanCompensationNone;

  UIViewController *viewController = [[UIViewController alloc] init];

    WKWebView *theSongView = [[WKWebView alloc] initWithFrame:viewController.view.frame];
    [theSongView setTranslatesAutoresizingMaskIntoConstraints:NO];
    theSongView.frame = CGRectMake(0, 0, viewController.view.bounds.size.width, viewController.view.bounds.size.height);
       [viewController.view addSubview:theSongView];
       
//This is where the error occurs
[viewController.view addConstraint:[NSLayoutConstraint constraintWithItem:theSongView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:viewController.view.safeAreaLayoutGuide.bottomAnchor attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
           [viewController.view addConstraint:[NSLayoutConstraint constraintWithItem:theSongView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewController.view.safeAreaLayoutGuide.topAnchor attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
           [viewController.view addConstraint:[NSLayoutConstraint constraintWithItem:theSongView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:viewController.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]];
           [viewController.view addConstraint:[NSLayoutConstraint constraintWithItem:theSongView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:viewController.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]];
        self.secondWindow.rootViewController = viewController;
    
        [self.secondWindow makeKeyAndVisible];
       
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
           NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:selectedSong] stringByAppendingString:@".pdf"];
       
            NSURL *url = [NSURL fileURLWithPath:pdfPath];
            NSLog(@"%@",url);
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            [theSongView loadRequest:request];
          
    }

CodePudding user response:

The error message I get with your code includes:

Constraint items must each be a view or layout guide.

So, it's pretty clear where to look.

Formatting your first constraint for readability:

[viewController.view addConstraint:[
    NSLayoutConstraint constraintWithItem:theSongView
    attribute:NSLayoutAttributeBottom
    relatedBy:NSLayoutRelationEqual
    toItem:viewController.view.safeAreaLayoutGuide.bottomAnchor
    attribute:NSLayoutAttributeTop
    multiplier:1.0
    constant:0]];

You're trying to set the theSongView's Bottom constraint equal to a .bottomAnchor's Top constraint. Which is, of course, not what you want to do.

If you change that constraint (and fix the others) like this:

[viewController.view addConstraint:[
    NSLayoutConstraint constraintWithItem:theSongView
    attribute:NSLayoutAttributeBottom
    relatedBy:NSLayoutRelationEqual
    toItem:viewController.view.safeAreaLayoutGuide
    attribute:NSLayoutAttributeBottom
    multiplier:1.0
    constant:0]];

You should be on your way.

I would strongly suggest, though, that you start using the more modern syntax for layout constraints:

UILayoutGuide *safeG = [viewController.view safeAreaLayoutGuide];

[NSLayoutConstraint activateConstraints:@[
    [theSongView.topAnchor constraintEqualToAnchor:safeG.topAnchor],
    [theSongView.leadingAnchor constraintEqualToAnchor:safeG.leadingAnchor],
    [theSongView.trailingAnchor constraintEqualToAnchor:safeG.trailingAnchor],
    [theSongView.bottomAnchor constraintEqualToAnchor:safeG.bottomAnchor],
]];
  • Related