1

I've only been developing on OSX 10.10+, I'm want my application to work on both 10.9 and 10.10+. I'm having the issue of viewDidLoad() is only available on 10.10+. How can I flexible views and view controllers to work on both?

From looking at the source code it looks like I need to override init? But when overriding init:nibName:nibBundleOrNil: but it also requires init:coder and that doesn't make much sense to me (it's undocumented in the source).

Jono
  • 3,393
  • 6
  • 33
  • 48
  • Would overloading `loadView` do the trick? You could also try adding a `didSet` for the view property, but that's straying into undocumented behaviour given that it's a read-only property. – Tommy Oct 12 '15 at 21:23

2 Answers2

1

Before 10.10 the NSViewController was basically doing nothing (it was the NSWindowController doing most of the job) ;) On 10.10 it gained the methods similar from iOS world (viewDidLoad...) and one really important thing, it was finally put automatically into NSResponder chain (NSApp sendAction:... will check if the viewController has the method).

So how to get the functionality?

  1. use awakeFromNib
  2. manually add view into responder chain (if you compile with 10.10 SDK then the view is added automatically on 10.10 and later; if you compile with 10.9 SDK you have to add it manually)
  3. use XIBs; you can't use storyboards -> they use 10.10 nsviewcontrollers -> dead end

So if you use storyboards it's a lot of work. If you don't have clean MVC/MVVM architecture then it's not worth.

Alternative is to double your classes pre10.10 and after10.10 but this means having the same code layed off twice (once using storyboards, once using XIBs).

EDIT:

As @geowar suggested you can override loadView. Mind that you still can't use storyboards and you have to manually add your viewController into responderChain

- (void)loadView
{
    [super loadView];

    // if we're running on 10.8 or older…
    if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_8) {
        [self viewDidLoad]; // call viewDidLoad (added in 10.9)
    }
}

Alternatively

- (void)setView:(NSView*)view {
    super.view = view;
    // if we're running on 10.8 or older…
    if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_8) {
        [self viewDidLoad]; // call viewDidLoad (added in 10.9)
    }
}
@end

EDIT2:

awakeFromNib is called after loadView (which gets the new view from xib and instantiates it). As suggested by @Daij-Djan another solution is to override setter.

Advice for People who Are Looking for -viewWillLoad and -viewDidLoad Methods in NSViewController

Even though NSWindowController has -windowWillLoad and -windowDidLoad methods for you to override the NSViewController class introduced in Mac OS 10.5 does not have corresponding -viewWillLoad and -viewDidLoad methods. You can override -[NSViewController loadView] to customize what happens immediately before or immediately after nib loading done by a view controller.

enter image description here

Marek H
  • 5,173
  • 3
  • 31
  • 42
0

to have thee equivalent of 10.10 on 10.9 write a VC like this

@interface MyViewController : NSViewController 
@end

@implementation MyViewController 
- (void)setView:(NSView*)v {
    super.view = v;
    // if we're running on 10.8 or older…
    if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_8) {
        [self viewDidLoad]; // call viewDidLoad (added in 10.9)
    }
}
@end
Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • You are correct but you can't call this equivalent. You can't get the same functionality of NSViewController behaviour just by doing this. Especially if he uses storyboard which is a dead end for 10.9. – Marek H Oct 14 '15 at 16:50
  • why? if that doesn't suffice, he can even go and override awakeFromNib if setView isn't called. don't get it :) – Daij-Djan Oct 14 '15 at 23:19
  • 1
    In 97 percent cases it's enough and you are 100 percent correct ;) – Marek H Oct 15 '15 at 07:23