FIXED : CPBinder subclasses were keeping references to the source object in a class var.

This could cause memory leaks and was unnecessarily verbose.
CPPopUpButton , CPRadio and CPSegmentedControl now use a generic CPBinder method for searching the binder involved when the control is asked to reverse set the binding, typically after a user interaction.
Fixes #2199
TODO: prevent user to bind multiple selection bindings when these bindings are exclusive.
This commit is contained in:
cacaodev
2014-09-06 20:35:41 +02:00
parent a3796fe128
commit e051d02ad3
6 changed files with 2088 additions and 792 deletions
+1 -23
View File
@@ -773,7 +773,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)_reverseSetBinding
{
[_CPPopUpButtonSelectionBinder reverseSetValueForObject:self];
[_CPPopUpButtonSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
[super _reverseSetBinding];
}
@@ -929,30 +929,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
@end
var binderForObject = {};
@implementation _CPPopUpButtonSelectionBinder : CPBinder
{
CPString _selectionBinding @accessors;
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
if (self)
{
binderForObject[[aSource UID]] = self;
_selectionBinding = aName;
}
return self;
}
+ (void)reverseSetValueForObject:(id)aSource
{
var binder = binderForObject[[aSource UID]];
[binder reverseSetValueFor:[binder _selectionBinding]];
}
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
+1 -23
View File
@@ -356,7 +356,7 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
[_selectedRadio setState:CPOffState];
_selectedRadio = aRadio;
[_CPRadioGroupSelectionBinder reverseSetValueForObject:self];
[_CPRadioGroupSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
}
@end
@@ -409,30 +409,8 @@ var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
@end
var binderForObject = {};
@implementation _CPRadioGroupSelectionBinder : CPBinder
{
CPString _selectionBinding @accessors;
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
if (self)
{
binderForObject[[aSource UID]] = self;
_selectionBinding = aName;
}
return self;
}
+ (void)reverseSetValueForObject:(id)aSource
{
var binder = binderForObject[[aSource UID]];
[binder reverseSetValueFor:[binder _selectionBinding]];
}
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
+13 -25
View File
@@ -49,6 +49,7 @@ CPSegmentSwitchTrackingMomentary = 2;
unsigned _trackingSegment;
BOOL _trackingHighlighted;
BOOL _hasBinding;
}
+ (CPString)defaultThemeClass
@@ -107,14 +108,22 @@ CPSegmentSwitchTrackingMomentary = 2;
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
{
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
else
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
return;
}
if (_hasBinding)
[_CPSegmentedControlBinder unbindAllForObject:self];
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
_hasBinding = YES;
}
- (void)_reverseSetBinding
{
[_CPSegmentedControlBinder reverseSetValueForObject:self];
[_CPSegmentedControlBinder _reverseSetValueFromExclusiveBinderForObject:self];
}
/*!
@@ -948,31 +957,10 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@end
var CPSegmentedControlBindersMap = {},
CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
var CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
@implementation _CPSegmentedControlBinder : CPBinder
{
CPString _selectionBinding @accessors(readonly, getter=selectionBinding);
}
+ (void)reverseSetValueForObject:(id)aSource
{
var binder = CPSegmentedControlBindersMap[[aSource UID]];
[binder reverseSetValueFor:[binder selectionBinding]];
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
if (self)
{
CPSegmentedControlBindersMap[[aSource UID]] = self;
_selectionBinding = aName;
}
return self;
}
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
@@ -6,6 +6,8 @@
* Copyright 2012, Your Company All rights reserved.
*/
CPLogRegister(CPLogConsole)
@import <Foundation/CPObject.j>
@implementation AppController : CPObject
@@ -30,10 +32,10 @@
- (id)newObject
{
var randIndex = FLOOR(RAND()*3),
randLabel = ["un", "deux", "trois", nil][FLOOR(RAND()*4)],
randTag = FLOOR(RAND()*3);
var randIndex = FLOOR(RAND() * 3),
randLabel = ["Label1", "Label2", "Label3", nil][FLOOR(RAND() * 4)],
randTag = FLOOR(RAND() * 3);
return [CPDictionary dictionaryWithObjectsAndKeys:randIndex, @"index", randLabel, @"label", randTag, @"tag"];
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff