2013-03-26 4 views
4

Я работаю над базой кода связки — не приложение —, где разработка началась 10.4 и требуется для работы 10.4, но работает до 10.8. Он загружает свои представления из файлов nib вручную, и я только недавно понял, что существует значительная утечка памяти, потому что перья используют привязки и связывают с владельцем файла, создавая ссылочные циклы и препятствуя освобождению класса владельца файла. Я думаю, что это усугубляется тем, что “ файл ' s владелец ” загрузить свой собственный наконечник.NSViewController на Mac OS X 10.4

я загрузить наконечники, используя следующий код (этот код в базовый классе и подклассы переопределить +nibName):

NSString *nibName = [[self class] nibName]; 
NSNib *nib = [[NSNib alloc] initWithNibNamed:nibName bundle:myBundle]; 
[nib instantiateNibWithOwner:self topLevelObjects:&topLevelObjects]; 

Так как у меня целевая 10.4, я неспособен использовать NSViewController. Я думаю, мне нужно будет реализовать свой собственный класс контроллера вида, но как я могу избежать циклов ссылок, поскольку обещает сделать класс NSViewController? Если диспетчер представлений является владельцем файла nib “ ”, то не буду ли я просто нажимать циклы ссылок из моего текущего класса на мои контроллеры представлений? Что делает NSViewController для предотвращения этого?

ответ

1

Я рекомендую вам использовать только NSWindowController или пользовательский подкласс.Ваш подкласс может иметь выход view и KVO-совместимый объект representedObject. Этого достаточно для 10.4-совместимой замены.

2

NSViewController абсолютно ничего особенного в отношении управления памятью или даже для объектов верхнего уровня. Он просто обеспечивает безопасное место для загрузки наконечника, а затем сохраняет его содержимое в памяти на протяжении жизненного цикла Nib, что означает, что сам класс немного больше, чем внешний владелец файла. Просто для ударов я переопределил класс и закомментировал интересные биты. Некоторые вещи, я просто удалился, потому что он был настолько взломан, что не стоило реализовывать, или так не использовался, что он не требовал повторного создания. Полный класс, с документацией и комментариями, можно найти here;

@interface CFIViewController : NSResponder <NSCoding> { 
@private 
    NSString *_nibName; 
    NSBundle *_nibBundle; 
    id _representedObject; 
    NSString *_title; 
    IBOutlet NSView *view; 
    NSArray *_topLevelObjects; 
    id _autounbinder; 
    //NSString *_designNibBundleIdentifier; 
} 

- (id)initWithNibName:(NSString*)nibName bundle:(NSBundle *)nibBundleOrNil; 

- (void)setRepresentedObject:(id)representedObject; 
- (id)representedObject; 

- (void)setTitle:(NSString *)title; 
- (NSString *)title; 

- (NSView *)view; 
- (void)loadView; 

- (NSString *)nibName; 
- (NSBundle *)nibBundle; 

- (void)setView:(NSView *)view; 

@end 

@implementation CFIViewController 

- (void)loadView { 
    NSArray *topLevelObjects = nil; 

    NSNib *loadedNib = [[[NSNib alloc]initWithNibNamed:self.nibName bundle:self.nibBundle]autorelease]; 
    if (loadedNib == nil) { 
     [NSException raise:NSInternalInconsistencyException format:@"-[%@ %@]", NSStringFromClass(self.class), NSStringFromSelector(_cmd)]; 
     return; 
    } 

    BOOL loaded = NO; 


#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 
    loaded = [loadedNib instantiateWithOwner:self topLevelObjects:&topLevelObjects]; 
#else 
    loaded = [loadedNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjects]; 
#endif 

    if (loaded) { 
     [self _setTopLevelObjects:topLevelObjects]; 
     [topLevelObjects makeObjectsPerformSelector:@selector(release)]; 
    } else { 
     [NSException raise:NSInternalInconsistencyException format:@"CFIViewController could not instantiate the %@ nib.", self.nibName]; 
    } 

    if (self.view != nil) { 
     [self viewDidLoad]; 
     return; 
    } 

    [NSException raise:NSInternalInconsistencyException format:@"-[%@ %@]", NSStringFromClass(self.class), NSStringFromSelector(_cmd)]; 
} 

@end 

Это действительно простой механизм. Все NSViewController действительно добавляет к какой-либо метафоре контроллера в Cocoa - это способность работать с NSDocument, и это основополагающее свойство Data Data беспорядочно.

Если диспетчер представлений является владельцем файла «nib», я бы вместо этого просто нажимал циклы ссылок из текущего класса на мои контроллеры представлений? Что делает NSViewController для предотвращения этого?

NSViewController обрабатывает сохранение объектов верхнего уровня одним из самых интересных способов, которые я видел. Когда он получает ссылку на массив, содержащий их, он делает мелкую копию массива, а затем -release - все объекты старого массива. Фактически, NSViewController захватывает каждую ссылку на объекты с замораживанием NIB от NSCoder, тем самым гарантируя безопасное освобождение, когда массив уходит в -dealloc.

Однако, когда дело доходит до привязок, NSViewController имеет внутренний геттер для подкласса NSProxy с именем NSAutounbinder, который KVO ищет при связывании и развязывании объектов. Путем настройки выпуска и предоставления геттера для внутреннего указателя автозапуска, классы контроллеров могут освобождать себя и свои привязки без боя. Абсолютно не рекомендуется использовать реализацию в CFIViewController для будущих выпусков ОС X без проверки того, что KVO по-прежнему ищет автозапуск getter, но для большинства других выпусков он выглядит нормально. CFIViewController предоставляет возможность использовать внутренний класс NSAutoUnbinder с последней фиксацией, тем самым разрешая любые циклы сохранения привязок.

+0

Это действительно намного больше усилий, чем я ожидал, что кто-нибудь запустит! Спасибо за это, я изучу его. Когда будет доступна щедрость, я дам вам дополнительные очки за усилия. – dreamlax

+0

@dreamlax Спасибо за это! Мне действительно нравится смотреть на внутренности AppKit и сделать его немного более управляемым. Не стесняйтесь использовать это в любых будущих проектах. – CodaFi

+0

Если я приму свой ответ, теперь опция раздачи исчезает, поэтому я временно не принял ее (но не волнуйся, я вернусь!) – dreamlax

Смежные вопросы