Skip to content

Commit 675a9f5

Browse files
committed
2 parents 3c8a1aa + da1cbb5 commit 675a9f5

File tree

9 files changed

+530
-16
lines changed

9 files changed

+530
-16
lines changed

ReactiveUI.Platforms/Cocoa/CocoaDefaultPropertyBinding.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public Tuple<string, int> GetPropertyForControl(object control)
1919
// NB: These are intentionally arranged in priority order from most
2020
// specific to least specific.
2121
#if UIKIT
22-
var items = new[] {
22+
var items = new[] {
2323
new { Type = typeof(UISlider), Property = "Value" },
2424
new { Type = typeof(UITextView), Property = "Text" },
2525
new { Type = typeof(UITextField), Property = "Text" },

ReactiveUI.Platforms/Cocoa/KVOObservableForProperty.cs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,42 @@ namespace ReactiveUI.Cocoa
2626
/// </summary>
2727
public class KVOObservableForProperty : ICreatesObservableForProperty
2828
{
29+
static readonly MemoizingMRUCache<Tuple<Type, string>, bool> declaredInNSObject;
30+
31+
static KVOObservableForProperty()
32+
{
33+
var monotouchAssemblyName = typeof(NSObject).Assembly.FullName;
34+
35+
declaredInNSObject = new MemoizingMRUCache<Tuple<Type, string>, bool>((pair, _) => {
36+
var thisType = pair.Item1;
37+
38+
// Types that aren't NSObjects at all are uninteresting to us
39+
if (typeof(NSObject).IsAssignableFrom(thisType) == false) {
40+
return false;
41+
}
42+
43+
while(thisType != null) {
44+
if (thisType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Any(x => x.Name == pair.Item2)) {
45+
// NB: This is a not-completely correct way to detect if
46+
// an object is defined in an Obj-C class (it will fail if
47+
// you're using a binding to a 3rd-party Obj-C library).
48+
return thisType.Assembly.FullName == monotouchAssemblyName;
49+
}
50+
51+
thisType = thisType.BaseType;
52+
}
53+
54+
// The property doesn't exist at all
55+
return false;
56+
}, RxApp.BigCacheLimit);
57+
}
58+
59+
2960
public int GetAffinityForObject(Type type, string propertyName, bool beforeChanged = false)
3061
{
31-
// NB: There is no way to know up-front whether a given property is
32-
// KVO-observable. This is Unfortunate™.
33-
return typeof (NSObject).IsAssignableFrom(type) ? 4 : 0;
62+
lock (declaredInNSObject) {
63+
return declaredInNSObject.Get(Tuple.Create(type, propertyName)) ? 15 : 0;
64+
}
3465
}
3566

3667
public IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, string propertyName, bool beforeChanged = false)

ReactiveUI.Platforms/Cocoa/UIKitObservableForProperty.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ public class UIKitObservableForProperty : UIKitObservableForPropertyBase
1616

1717
public UIKitObservableForProperty ()
1818
{
19-
Register(typeof(UIControl), "Value", 9, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
20-
Register(typeof(UITextField), "Text", 10, (s, p) => ObservableFromNotification(s, p, UITextField.TextFieldTextDidChangeNotification));
21-
Register(typeof(UIDatePicker), "Date", 10, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
22-
Register(typeof(UISegmentedControl), "SelectedSegment", 10, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
23-
Register(typeof(UISwitch), "On", 10, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
24-
Register(typeof(UISegmentedControl), "SelectedSegment", 10, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
19+
Register(typeof(UIControl), "Value", 20, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
20+
Register(typeof(UITextField), "Text", 30, (s, p) => ObservableFromNotification(s, p, UITextField.TextFieldTextDidChangeNotification));
21+
Register(typeof(UIDatePicker), "Date", 30, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
22+
Register(typeof(UISegmentedControl), "SelectedSegment", 30, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
23+
Register(typeof(UISwitch), "On", 30, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
24+
Register(typeof(UISegmentedControl), "SelectedSegment", 30, (s, p)=> ObservableFromUIControlEvent(s, p, UIControlEvent.ValueChanged));
2525

2626
// Warning: This will stomp the Control's delegate
27-
Register(typeof(UITabBar), "SelectedItem", 10, (s, p) => ObservableFromEvent(s, p, "ItemSelected"));
27+
Register(typeof(UITabBar), "SelectedItem", 30, (s, p) => ObservableFromEvent(s, p, "ItemSelected"));
2828

2929
// Warning: This will stomp the Control's delegate
30-
Register(typeof(UISearchBar), "Text", 10, (s, p) => ObservableFromEvent(s, p, "TextChanged"));
30+
Register(typeof(UISearchBar), "Text", 30, (s, p) => ObservableFromEvent(s, p, "TextChanged"));
3131
}
3232
}
3333
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using Xunit;
3+
using ReactiveUI.Cocoa;
4+
5+
namespace ReactiveUI.Tests
6+
{
7+
public class FooController : ReactiveViewController, IViewFor<PropertyBindViewModel>
8+
{
9+
PropertyBindViewModel _ViewModel;
10+
public PropertyBindViewModel ViewModel {
11+
get { return _ViewModel; }
12+
set { this.RaiseAndSetIfChanged(ref _ViewModel, value); }
13+
}
14+
15+
object IViewFor.ViewModel {
16+
get { return ViewModel; }
17+
set { ViewModel = (PropertyBindViewModel)value; }
18+
}
19+
}
20+
21+
public class KVOBindingTests
22+
{
23+
[Fact]
24+
public void MakeSureKVOBindingsBindToKVOThings()
25+
{
26+
var input = new FooController();
27+
var fixture = new KVOObservableForProperty();
28+
29+
Assert.NotEqual(0, fixture.GetAffinityForObject(typeof(FooController), "View"));
30+
Assert.Equal(0, fixture.GetAffinityForObject(typeof(FooController), "ViewModel"));
31+
}
32+
}
33+
}

ReactiveUI.Tests/ReactiveUI.Tests_Monotouch.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<OutputType>Exe</OutputType>
1111
<RootNamespace>ReactiveUI.Tests</RootNamespace>
1212
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
13-
<AssemblyName>ReactiveUI_Tests_Monotouch</AssemblyName>
1413
</PropertyGroup>
1514
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
1615
<DebugSymbols>true</DebugSymbols>
@@ -147,6 +146,7 @@
147146
<Compile Include="ReactiveNotifyPropertyChangedMixinTest.cs" />
148147
<Compile Include="Cocoa\PropertyBindingTestViews.cs" />
149148
<Compile Include="PropertyBindingTest.cs" />
149+
<Compile Include="Cocoa\KVOBindingTests.cs" />
150150
</ItemGroup>
151151
<ItemGroup>
152152
<ProjectReference Include="..\ReactiveUI.Platforms\ReactiveUI.Cocoa_Monotouch.csproj">

0 commit comments

Comments
 (0)