CALayer在调用removeFromSuperlayer后仍然显示

时间:2014-05-30 12:00:31

标签: ios objective-c macos cocoa

我在同步一组函数调用时遇到了一些问题。我想要实现的是

  1. 显示我的第一个视图并允许它捕获鼠标坐标
  2. 删除我的第一个视图,然后根据第一步中的鼠标坐标捕获CGWindowListCreateImage的屏幕截图。
  3. 显示我的第二个视图。
  4. 除了屏幕截图中没有删除第一个视图外,一切正常。我不确定是什么导致了这个问题。第一个视图确实有一些基本的核心动画。我已经覆盖了drawRect方法来应用一些自定义动画。我已经尝试在以下内容中运行代码,认为问题可能是由于runloop无法在屏幕截图之前删除视图。

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    
    }];
    

    这是我处理转换的整个功能。在调试器中运行它并在函数开头设置断点并逐行跳过它时,在屏幕捕获期间始终会删除第一个视图。因此,为什么我觉得这是导致我问题的同步问题。

    - (void)mouseUp:(NSEvent *)theEvent{
    
        //Get point based on screen cordiates not releative to any window or view.
        _endPoint = [NSEvent mouseLocation];
    
        //Remove the shape layer from screen
        [self.shapeLayer removeAllAnimations];
        [self.shapeLayer removeFromSuperlayer];
         self.shapeLayer = nil;
    
        //Grab a pointer to the window so we can add the View 2
        NSWindow * win = self.view.window;
    
        //Order the window out so that we can capture the screen without capturing our transparent view
        //[win orderOut:nil];
        //set the current view to hidden so that it does not conflic with the screen capture
        //[self.view setHidden:YES];
    
         //proceed to remove it fromt the superview as we nolonger need it
         [self.view removeFromSuperview];
    
    
    
        //Get the rect of the main screen so we can calculate our capture rectangle
        NSRect screenRect =  [[NSScreen mainScreen]frame];
    
        //Capture rect
    
        _squareRect = CGMakeRect(blah,balh,blah,blah);
    
        //Capture the screen with the specified rectangle
        NSImage * image = [self captureScreen:_squareRect];
        [self addToPastBoard:image];
    
        //Create the Edit view and inject the image
        EditControlsViewController *editViewController = [[EditControlsViewController alloc]initWithNibName:@"EditControlsViewController" bundle:[NSBundle mainBundle] image:image];
    
        //Set the frame and bounds of the edit view
        [editViewController.view setFrame:self.view.window.frame];
        [editViewController.view setBounds:self.view.window.frame];
        editViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
        [editViewController.imgView setImage:image];
    
        //Since our image has been captured order the window back to front;
        //[win orderFront:nil];
    
        //Replace the current view with the new view. Since we previously removed our view just add the new
        //view as a subview of the content view
        [win.contentView addSubview:editViewController.view positioned:NSWindowAbove relativeTo:nil];
    
        NSView * editView = editViewController.view;
    
    
        NSDictionary *views = NSDictionaryOfVariableBindings(editView);
        [win.contentView addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[editView]|"
                                                 options:0
                                                 metrics:nil
                                                   views:views]];
    
        [win.contentView addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[editView]|"
                                                 options:0
                                                 metrics:nil
                                                   views:views]];
    
        //beautiful way to help debug constraints;
        //[win visualizeConstraints:[win.contentView constraints]];
    
    
    }
    

    removeFromSuperLayer是异步调用吗?

    我可以做些什么来让视图完成删除?

    任何指针都将非常感激。提前谢谢。

1 个答案:

答案 0 :(得分:1)

屏幕的所有更新都是异步进行的。您可以更改屏幕状态,然后在下一次通过事件循环时,您的更改将呈现在屏幕上。在您的代码中,您应用更改,然后在更改发生之前捕获屏幕的CURRENT状态。

获取捕获屏幕截图的代码,将其放在单独的方法中,然后使用[self performSelect: @selector(screenshot) witObject: nil afterDelay: 0]调用它。在应用了屏幕更改后,该调用将您的选择器排队,以便在下一次通过事件循环的END处调用。

您也可以使用

dispatch_after(DISPATCH_TIME_NOW, 0, dispatch_get_main_queue(), ^
  {
     //Code to execute after servicing the event loop
  }
);

我在NSObject上有一个类,它实现了一个方法performBlockOnMainQueue:afterDelay:它使用的代码与上面的dispatch_after调用非常相似。由于它使用块,因此延迟后要调用的代码是内联的,并且可以访问封闭范围内的变量。

编辑:您可以在"RandomBlobs" project on github

中找到NSObject + performBlockAfterDelay类别