diff --git a/AppKit/CPClipView.j b/AppKit/CPClipView.j index 7cc52d2bc..8503c4cc5 100644 --- a/AppKit/CPClipView.j +++ b/AppKit/CPClipView.j @@ -47,18 +47,7 @@ if (_documentView) { - var defaultCenter = [CPNotificationCenter defaultCenter]; - - [defaultCenter - removeObserver:self - name:CPViewFrameDidChangeNotification - object:_documentView]; - - [defaultCenter - removeObserver:self - name:CPViewBoundsDidChangeNotification - object:_documentView]; - + [self _removeObserverDocumentView:_documentView]; [_documentView removeFromSuperview]; } @@ -91,6 +80,43 @@ object:_documentView]; } +- (void)_removeObserverDocumentView:(CPView)aDocumentView +{ + var defaultCenter = [CPNotificationCenter defaultCenter]; + + [defaultCenter + removeObserver:self + name:CPViewFrameDidChangeNotification + object:_documentView]; + + [defaultCenter + removeObserver:self + name:CPViewBoundsDidChangeNotification + object:_documentView]; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + if (_documentView) + [self _observeDocumentView]; +} + +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + + if (_documentView) + [self _removeObserverDocumentView:_documentView]; +} + /*! Returns the document view. */ diff --git a/AppKit/CPColorWell.j b/AppKit/CPColorWell.j index 8d8132f3a..15fa5343b 100644 --- a/AppKit/CPColorWell.j +++ b/AppKit/CPColorWell.j @@ -86,14 +86,12 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv _active = NO; _color = [CPColor whiteColor]; [self setBordered:YES]; - - [self _registerForNotifications]; } return self; } -- (void)_registerForNotifications +- (void)_registerNotifications { var defaultCenter = [CPNotificationCenter defaultCenter]; @@ -110,6 +108,22 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv object:[CPColorPanel sharedColorPanel]]; } +- (void)_removeNotifications +{ + var defaultCenter = [CPNotificationCenter defaultCenter]; + + [defaultCenter + removeObserver:self + name:_CPColorWellDidBecomeExclusiveNotification + object:nil]; + + [defaultCenter + removeObserver:self + name:CPWindowWillCloseNotification + object:[CPColorPanel sharedColorPanel]]; + +} + /*! Sets whether the color well is bordered. */ @@ -312,6 +326,28 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv [contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]]; } + +#pragma mark - +#pragma mark Observers method + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + [self _registerNotifications]; +} + +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + [self _removeNotifications]; +} + @end @implementation CPColorWellValueBinder : CPBinder @@ -363,8 +399,6 @@ var CPColorWellColorKey = "CPColorWellColorKey", _active = NO; _color = [aCoder decodeObjectForKey:CPColorWellColorKey]; [self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]]; - - [self _registerForNotifications]; } return self; diff --git a/AppKit/CPDatePicker/_CPDatePickerTextField.j b/AppKit/CPDatePicker/_CPDatePickerTextField.j index b8cc6dfdd..77f541212 100644 --- a/AppKit/CPDatePicker/_CPDatePickerTextField.j +++ b/AppKit/CPDatePicker/_CPDatePickerTextField.j @@ -92,8 +92,6 @@ var CPZeroKeyCode = 48, [_stepper setAction:@selector(_clickStepper:)]; [self addSubview:_stepper]; - [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_datePickerElementTextFieldBecomeFirstResponder:) name:CPDatePickerElementTextFieldBecomeFirstResponder object:self]; - [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -414,6 +412,30 @@ var CPZeroKeyCode = 48, [_datePickerElementView setNeedsLayout]; } + +#pragma mark - +#pragma mark Override observers + +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + + [[CPNotificationCenter defaultCenter] removeObserver:self name:CPDatePickerElementTextFieldBecomeFirstResponder object:self]; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_datePickerElementTextFieldBecomeFirstResponder:) name:CPDatePickerElementTextFieldBecomeFirstResponder object:self]; +} + @end @@ -524,8 +546,6 @@ var CPZeroKeyCode = 48, [self addSubview: _textFieldSeparatorThree]; [self addSubview: _textFieldSeparatorFour]; - [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_datePickerElementTextFieldAMPMChangedNotification:) name:CPDatePickerElementTextFieldAMPMChangedNotification object:_textFieldPMAM]; - [self setNeedsLayout]; } @@ -539,6 +559,30 @@ var CPZeroKeyCode = 48, } +#pragma mark - +#pragma mark Override observers + +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + + [[CPNotificationCenter defaultCenter] removeObserver:self name:CPDatePickerElementTextFieldAMPMChangedNotification object:_textFieldPMAM]; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_datePickerElementTextFieldAMPMChangedNotification:) name:CPDatePickerElementTextFieldAMPMChangedNotification object:_textFieldPMAM]; +} + + #pragma mark - #pragma mark Setter Getter methods diff --git a/AppKit/CPRuleEditor/_CPRuleEditorViewSliceRow.j b/AppKit/CPRuleEditor/_CPRuleEditorViewSliceRow.j index 45c260d25..30470d5c6 100644 --- a/AppKit/CPRuleEditor/_CPRuleEditorViewSliceRow.j +++ b/AppKit/CPRuleEditor/_CPRuleEditorViewSliceRow.j @@ -65,8 +65,6 @@ [self addSubview:_subtractButton]; [self setAutoresizingMask:CPViewWidthSizable]; - - [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil]; } - (CPButton)_createRowButton @@ -491,6 +489,26 @@ [self layoutSubviews]; } +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil]; +} + +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + + [[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:nil]; +} + - (void)drawRect:(CGRect)rect { [super drawRect:rect]; @@ -516,4 +534,4 @@ [self _sendRuleAction:nil]; } -@end \ No newline at end of file +@end diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index d7346f9ed..c26e79140 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -119,16 +119,28 @@ var RECENT_SEARCH_PREFIX = @" "; _canResignFirstResponder = YES; } -- (void)viewWillMoveToSuperview:(CPView)aView + +#pragma mark - +#pragma mark Override observers + +- (void)_removeObservers { - [super viewWillMoveToSuperview:aView]; + if (!_isObserving) + return; + + [super _removeObservers]; - // First we remove any observer that may have been in place to avoid memory leakage. [[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self]; +} - // Register the observe here if we need to. - if (aView) - [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self]; +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self]; } // Managing Buttons diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 32b24ef97..2349099c6 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -473,8 +473,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!_sortDescriptors) _sortDescriptors = []; - - [self _startObservingFirstResponder]; } /*! @@ -4456,6 +4454,8 @@ Your delegate can implement this method to avoid subclassing the tableview to ad */ - (void)viewWillMoveToSuperview:(CPView)aView { + [super viewWillMoveToSuperview:aView]; + var superview = [self superview], defaultCenter = [CPNotificationCenter defaultCenter]; @@ -5128,6 +5128,24 @@ Your delegate can implement this method to avoid subclassing the tableview to ad return hit; } +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + [self _stopObservingFirstResponder]; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + [self _startObservingFirstResponder]; +} + - (void)_startObservingFirstResponder { [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_firstResponderDidChange:) name:_CPWindowDidChangeFirstResponderNotification object:[self window]]; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 134d65816..89de8be0a 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -834,6 +834,26 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); } } +- (void)_removeObservers +{ + if (!_isObserving) + return; + + [super _removeObservers]; + [self _setObserveWindowKeyNotifications:NO]; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + [super _addObservers]; + + if ([self window] === self) + [self _setObserveWindowKeyNotifications:YES]; +} + - (void)_windowDidResignKey:(CPNotification)aNotification { if (![[self window] isKeyWindow]) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 3ceb92f6e..9de2e67bc 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -228,6 +228,8 @@ var CPViewFlags = { }, Function _toolTipFunctionIn; Function _toolTipFunctionOut; BOOL _toolTipInstalled; + + BOOL _isObserving; } /* @@ -508,8 +510,12 @@ var CPViewFlags = { }, [CPException raise:CPInvalidArgumentException reason:"can't insert a subview in duplicate (probably partially decoded)"]; #endif + // Notify the subview that it will be moving. + [aSubview viewWillMoveToSuperview:self]; + // We will have to adjust the z-index of all views starting at this index. - var count = _subviews.length; + var count = _subviews.length, + lastWindow; // Dirty the key view loop, in case the window wants to auto recalculate it [[self window] _dirtyKeyViewLoop]; @@ -537,14 +543,12 @@ var CPViewFlags = { }, } else { + var superview = aSubview._superview; + + lastWindow = [superview window]; + // Remove the view from its previous superview. - [aSubview removeFromSuperview]; - - // Set the subview's window to our own. - [aSubview _setWindow:_window]; - - // Notify the subview that it will be moving. - [aSubview viewWillMoveToSuperview:self]; + [aSubview _removeFromSuperview]; // Set ourselves as the superview. aSubview._superview = self; @@ -577,6 +581,15 @@ var CPViewFlags = { }, if (![aSubview isHidden] && [self isHiddenOrHasHiddenAncestor]) [aSubview _notifyViewDidHide]; + [aSubview viewDidMoveToSuperview]; + + // Set the subview's window to our own. + if (_window) + [aSubview _setWindow:_window]; + + if (!_window && lastWindow) + [aSubview _setWindow:nil]; + // This method might be called before we are fully unarchived, in which case the theme state isn't set up yet // and none of the below matters anyhow. if (_themeState) @@ -592,8 +605,6 @@ var CPViewFlags = { }, [aSubview _notifyWindowDidResignKey]; } - [aSubview viewDidMoveToSuperview]; - [self didAddSubview:aSubview]; } @@ -610,6 +621,18 @@ var CPViewFlags = { }, Does nothing if there's no container view. */ - (void)removeFromSuperview +{ + var superview = _superview; + + [self viewWillMoveToSuperview:nil]; + [self _removeFromSuperview]; + [self viewDidMoveToSuperview]; + + if (superview) + [self _setWindow:nil]; +} + +- (void)_removeFromSuperview { if (!_superview) return; @@ -634,8 +657,6 @@ var CPViewFlags = { }, [self _notifyViewDidResignFirstResponder]; _superview = nil; - - [self _setWindow:nil]; } /*! @@ -645,14 +666,14 @@ var CPViewFlags = { }, */ - (void)replaceSubview:(CPView)aSubview with:(CPView)aView { - if (aSubview._superview !== self) + if (aSubview._superview !== self || aSubview === aView) return; var index = [_subviews indexOfObjectIdenticalTo:aSubview]; - [aSubview removeFromSuperview]; - [self _insertSubview:aView atIndex:index]; + + [aSubview removeFromSuperview]; } - (void)setSubviews:(CPArray)newSubviews @@ -727,9 +748,6 @@ var CPViewFlags = { }, /* @ignore */ - (void)_setWindow:(CPWindow)aWindow { - if (_window === aWindow) - return; - [[self window] _dirtyKeyViewLoop]; // Clear out first responder if we're the first responder and leaving. @@ -803,6 +821,10 @@ var CPViewFlags = { }, */ - (void)viewWillMoveToSuperview:(CPView)aView { + [self _removeObservers]; + + if (aView) + [self _addObservers]; } /*! @@ -821,6 +843,32 @@ var CPViewFlags = { }, { } +- (void)_removeObservers +{ + if (!_isObserving) + return; + + var count = [_subviews count]; + + while (count--) + [_subviews[count] _removeObservers]; + + _isObserving = NO; +} + +- (void)_addObservers +{ + if (_isObserving) + return; + + var count = [_subviews count]; + + while (count--) + [_subviews[count] _addObservers]; + + _isObserving = YES; +} + /*! Returns the menu item containing the receiver or one of its ancestor views. @return a menu item, or \c nil if the view or one of its ancestors wasn't found @@ -2964,10 +3012,10 @@ setBoundsOrigin: - (BOOL)unsetThemeState:(ThemeState)aState { - if (aState && aState.isa && [aState isKindOfClass:CPArray]) + if (aState && aState.isa && [aState isKindOfClass:CPArray]) aState = CPThemeState.apply(null, aState); - var oldThemeState = _themeState + var oldThemeState = _themeState; _themeState = _themeState.without(aState); if (oldThemeState === _themeState) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 0e074ccb1..70fb8034e 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -901,6 +901,8 @@ CPTexturedBackgroundWindowMask - (void)_orderFront { + [[self contentView] _addObservers]; + #if PLATFORM(DOM) // -dw- if a sheet is clicked, the parent window should come up too if (_isSheet) @@ -960,6 +962,8 @@ CPTexturedBackgroundWindowMask if (!_isVisible) return; + [[self contentView] _removeObservers]; + if ([self isSheet]) { // -dw- as in Cocoa, orderOut: detaches the sheet and animates out diff --git a/Tests/AppKit/CPViewTest.j b/Tests/AppKit/CPViewTest.j index 509664c4b..3d1430492 100644 --- a/Tests/AppKit/CPViewTest.j +++ b/Tests/AppKit/CPViewTest.j @@ -4,14 +4,33 @@ [CPApplication sharedApplication] +var methodCalled; + @implementation CPViewTest : OJTestCase { CPView view; + CPView view1; + CPView view2; + CPView view3; + + CPWindow window; } - (void)setUp { + window = [[CPWindow alloc] initWithContentRect:CGRectMake(0.0, 0.0, 1000.0, 1000.0) styleMask:CPWindowNotSizable]; + view = [[CPView alloc] initWithFrame:CGRectMakeZero()]; + view1 = [[CPResponderView alloc] initWithFrame:CGRectMakeZero()]; + view2 = [[CPResponderView alloc] initWithFrame:CGRectMakeZero()]; + view3 = [[CPResponderView alloc] initWithFrame:CGRectMakeZero()]; + + [view1 setIdentifier:@"view1"]; + [view2 setIdentifier:@"view2"]; + [view3 setIdentifier:@"view3"]; + + methodCalled = []; + [super setUp]; } @@ -446,10 +465,213 @@ [self assertFalse:[subview hasThemeState:CPThemeStateFirstResponder]]; } +- (void)testWhenAddedSubviewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedSubviewWithoutWindowMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2"]; + + [view1 addSubview:view2]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedSubviewTwiceMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1", @"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + [[window contentView] addSubview:view1]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenRemovedSubviewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1"]; + + [view1 removeFromSuperview]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedSubviewThenRemovedSubviewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + + methodCalled = []; + [view1 removeFromSuperview]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedSubviewThenRemovedSubviewWithoutWindowMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1"]; + + [view1 addSubview:view2]; + + methodCalled = []; + [view1 removeFromSuperview]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2",@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2", "viewDidMoveToWindow_view1"]; + + [view1 addSubview:view2]; + [[window contentView] addSubview:view1]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsThenRemovedMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2", "viewDidMoveToWindow_view1"]; + + [view1 addSubview:view2]; + [[window contentView] addSubview:view1]; + + methodCalled = []; + [view1 removeFromSuperview]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsThenAddedTheViewToAnotherViewWithoutWindowMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", @"viewWillMoveToWindow_view1", @"viewDidMoveToWindow_view1", @"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", @"viewWillMoveToWindow_view1", @"viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + [view2 addSubview:view1]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedOneSubviewsWithSetSubviewsMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] setSubviews:[view1]]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsWithSetSubviewsMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1", @"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2"]; + + [[window contentView] setSubviews:[view1, view2]]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsThenSetSubviewsWithOneViewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2"]; + + [[window contentView] setSubviews:[view1, view2]]; + + methodCalled = []; + + [[window contentView] setSubviews:[view1]]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenAddedTwoSubviewsThenSetSubviewsWithTwoViewsMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2", @"viewWillMoveToSuperview_view3", @"viewDidMoveToSuperview_view3", "viewWillMoveToWindow_view3", "viewDidMoveToWindow_view3"]; + + [[window contentView] setSubviews:[view1, view2]]; + + methodCalled = []; + + [[window contentView] setSubviews:[view1, view3]]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenReplacedViewWithSameViewMethodCalled +{ + var expectedRestult = []; + + [[window contentView] addSubview:view1]; + + methodCalled = []; + + [[window contentView] replaceSubview:view1 with:view1]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenReplacedViewWithOtherViewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2", @"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + + methodCalled = []; + + [[window contentView] replaceSubview:view1 with:view2]; + + [self assert:expectedRestult equals:methodCalled]; +} + +- (void)testWhenReplacedViewWithOtherAddedViewMethodCalled +{ + var expectedRestult = [@"viewWillMoveToSuperview_view2", @"viewDidMoveToSuperview_view2", "viewWillMoveToWindow_view2", "viewDidMoveToWindow_view2", @"viewWillMoveToSuperview_view1", @"viewDidMoveToSuperview_view1", "viewWillMoveToWindow_view1", "viewDidMoveToWindow_view1"]; + + [[window contentView] addSubview:view1]; + [[window contentView] addSubview:view2]; + + methodCalled = []; + + [[window contentView] replaceSubview:view1 with:view2]; + + [self assert:expectedRestult equals:methodCalled]; +} + @end + @implementation CPResponderView : CPView +- (void)viewDidMoveToSuperview +{ + var string = @"viewDidMoveToSuperview_" + [self identifier]; + [methodCalled addObject:string]; +} + +- (void)viewDidMoveToWindow +{ + var string = @"viewDidMoveToWindow_" + [self identifier]; + [methodCalled addObject:string]; +} + +- (void)viewWillMoveToSuperview:(CPView)newSuperview +{ + var string = @"viewWillMoveToSuperview_" + [self identifier]; + [methodCalled addObject:string]; +} + +- (void)viewWillMoveToWindow:(CPWindow)newWindow +{ + var string = @"viewWillMoveToWindow_" + [self identifier]; + [methodCalled addObject:string]; +} + - (BOOL)acceptsFirstResponder { return YES;