Search code examples
objective-cnsviewappkitretainnsstackview

How to inject a NSStackView into the view hierarchy?


I have an OSX application written in Objective-C. It displays some NSView in a NSWindow, the problem is I cannot modify its code. The original model hierarchy looks like this:

NSWindow
|---> original NSView
      |---> (...)

I'd like to alter the hierarchy as follows:

NSWindow
|---> NSStackView
      |---> original NSView
      |     |---> (...)
      |---> some additional NSView (say NSTextField)

How can I display both the original NSView and the additional NSView next to each other, using NSStackView?

My current approach was more or less like this (the example is simplified):

- (void)createFirstView {
    NSTextField *label1 = [NSTextField labelWithString:@"First view."];
    [_window setContentView: label1];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // I cannot modify this procedure:
    [self createFirstView];

    // I can modify that:
    NSTextField *label2 = [NSTextField labelWithString:@"Second view."];

    NSView *firstView = [_window contentView];
    [firstView removeFromSuperview];
    NSStackView *st = [NSStackView stackViewWithViews:@[firstView, label2]];
    [_window setContentView:st];
}

Unfortunately the NSWindow after running this code shows only the "Second view" label:

Result


Solution

  • [_window setContentView:st] calls removeFromSuperview on the old content view and removeFromSuperview releases the view. [firstView removeFromSuperview] and [_window setContentView:st] will both release firstView.

    Solution: replace [firstView removeFromSuperview] by [_window setContentView:nil].

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
        // I cannot modify this procedure:
        [self createFirstView];
    
        // I can modify that:
        NSTextField *label2 = [NSTextField labelWithString:@"Second view."];
    
        NSView *firstView = [_window contentView];
        [_window setContentView:nil];
        NSStackView *st = [NSStackView stackViewWithViews:@[firstView, label2]];
        [_window setContentView:st];
    }