Skip to content

Commit 496e465

Browse files
committed
fixes and refactoring
1 parent 329cee8 commit 496e465

12 files changed

+316
-330
lines changed

UnityWeld/Binding/AbstractMemberBinding.cs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ public abstract class AbstractMemberBinding : MonoBehaviour, IMemberBinding
1414
{
1515
private bool _isInitCalled;
1616

17-
[SerializeField]
18-
private bool _isAutoConnection = true;
17+
[SerializeField] private bool _isAutoConnection = true;
1918

2019
/// <summary>
2120
/// Initialise this binding. Used when we first start the scene.
@@ -25,7 +24,7 @@ public virtual void Init()
2524
{
2625
_isInitCalled = true;
2726

28-
if (!gameObject.activeInHierarchy)
27+
if(!gameObject.activeInHierarchy)
2928
{
3029
return; //wait for enabling
3130
}
@@ -40,47 +39,50 @@ public virtual void Init()
4039
private object FindViewModel(string viewModelName)
4140
{
4241
var trans = transform;
43-
while (trans != null)
42+
while(trans != null)
4443
{
45-
var buffer = Buffer.Behaviours;
46-
trans.GetComponents<MonoBehaviour>(buffer);
47-
var monoBehaviourViewModel = buffer
48-
.FirstOrDefault(component => component.GetType().ToString() == viewModelName);
49-
if (monoBehaviourViewModel != null)
44+
using(var cache = trans.gameObject.GetComponentsWithCache<MonoBehaviour>(false))
5045
{
51-
return monoBehaviourViewModel;
52-
}
53-
54-
var providedViewModel = buffer
55-
.Select(component => component.GetViewModelData())
56-
.Where(component => component != null)
57-
.FirstOrDefault(
58-
viewModelData => viewModelData.TypeName == viewModelName &&
46+
var monoBehaviourViewModel = cache.Components
47+
.FirstOrDefault(component =>
48+
component.GetType().ToString() ==
49+
viewModelName);
50+
if(monoBehaviourViewModel != null)
51+
{
52+
return monoBehaviourViewModel;
53+
}
54+
55+
var providedViewModel = cache.Components
56+
.Select(component => component.GetViewModelData())
57+
.Where(component => component != null)
58+
.FirstOrDefault(
59+
viewModelData => viewModelData.TypeName == viewModelName &&
5960
#pragma warning disable 252,253 // Warning says unintended reference comparison, but we do want to compare references
60-
(object) viewModelData.Model != this
61+
(object)viewModelData.Model != this
6162
#pragma warning restore 252,253
62-
);
63+
);
6364

64-
if (providedViewModel != null)
65-
{
66-
return providedViewModel.Model;
65+
if(providedViewModel != null)
66+
{
67+
return providedViewModel.Model;
68+
}
6769
}
6870

6971
trans = trans.parent;
7072
}
7173

72-
throw new ViewModelNotFoundException(string.Format(
73-
"Tried to get view model {0} but it could not be found on "
74-
+ "object {1}. Check that a ViewModelBinding for that view model exists further up in "
75-
+ "the scene hierarchy. ", viewModelName, gameObject.name)
74+
throw new ViewModelNotFoundException(
75+
$"Tried to get view model {viewModelName} but it could not be found on " +
76+
$"object {gameObject.name}. Check that a ViewModelBinding for that view model exists further up in " +
77+
"the scene hierarchy. "
7678
);
7779
}
7880

7981
/// <summary>
8082
/// Make a property end point for a property on the view model.
8183
/// </summary>
8284
protected PropertyEndPoint MakeViewModelEndPoint(string viewModelPropertyName, string adapterId,
83-
AdapterOptions adapterOptions)
85+
AdapterOptions adapterOptions)
8486
{
8587
string propertyName;
8688
object viewModel;
@@ -94,10 +96,10 @@ protected PropertyEndPoint MakeViewModelEndPoint(string viewModelPropertyName, s
9496
/// Parse an end-point reference including a type name and member name separated by a period.
9597
/// </summary>
9698
protected static void ParseEndPointReference(string endPointReference, out string memberName,
97-
out string typeName)
99+
out string typeName)
98100
{
99101
var lastPeriodIndex = endPointReference.LastIndexOf('.');
100-
if (lastPeriodIndex == -1)
102+
if(lastPeriodIndex == -1)
101103
{
102104
throw new InvalidEndPointException(
103105
"No period was found, expected end-point reference in the following format: <type-name>.<member-name>. " +
@@ -109,12 +111,12 @@ protected static void ParseEndPointReference(string endPointReference, out strin
109111
memberName = endPointReference.Substring(lastPeriodIndex + 1);
110112
//Due to (undocumented) unity behaviour, some of their components do not work with the namespace when using GetComponent(""), and all of them work without the namespace
111113
//So to be safe, we remove all namespaces from any component that starts with UnityEngine
112-
if (typeName.StartsWith("UnityEngine."))
114+
if(typeName.StartsWith("UnityEngine."))
113115
{
114116
typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
115117
}
116118

117-
if (typeName.Length == 0 || memberName.Length == 0)
119+
if(typeName.Length == 0 || memberName.Length == 0)
118120
{
119121
throw new InvalidEndPointException(
120122
"Bad format for end-point reference, expected the following format: <type-name>.<member-name>. " +
@@ -127,13 +129,13 @@ protected static void ParseEndPointReference(string endPointReference, out strin
127129
/// Parse an end-point reference and search up the hierarchy for the named view-model.
128130
/// </summary>
129131
protected void ParseViewModelEndPointReference(string endPointReference, out string memberName,
130-
out object viewModel)
132+
out object viewModel)
131133
{
132134
string viewModelName;
133135
ParseEndPointReference(endPointReference, out memberName, out viewModelName);
134136

135137
viewModel = FindViewModel(viewModelName);
136-
if (viewModel == null)
138+
if(viewModel == null)
137139
{
138140
throw new ViewModelNotFoundException("Failed to find view-model in hierarchy: " + viewModelName);
139141
}
@@ -148,7 +150,7 @@ protected void ParseViewEndPointReference(string endPointReference, out string m
148150
ParseEndPointReference(endPointReference, out memberName, out boundComponentType);
149151

150152
view = GetComponent(boundComponentType);
151-
if (view == null)
153+
if(view == null)
152154
{
153155
throw new ComponentNotFoundException("Failed to find component on current game object: " +
154156
boundComponentType);
@@ -171,7 +173,7 @@ protected void ParseViewEndPointReference(string endPointReference, out string m
171173
/// </summary>
172174
protected void OnEnable()
173175
{
174-
if (!_isAutoConnection && !_isInitCalled)
176+
if(!_isAutoConnection && !_isInitCalled)
175177
{
176178
return;
177179
}

UnityWeld/Binding/BindingHelper.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
6+
namespace UnityWeld.Binding
7+
{
8+
public interface IComponentsCache : IDisposable{}
9+
10+
public interface IComponentsCache<T> : IComponentsCache
11+
{
12+
IList<T> Components { get; }
13+
}
14+
15+
public static class BindingHelper
16+
{
17+
private class ComponentsCache<T> : IComponentsCache<T>
18+
{
19+
public IList<T> Components { get; }
20+
public Type Type { get; }
21+
22+
public ComponentsCache(IList<T> cache)
23+
{
24+
Components = cache;
25+
Type = typeof(T);
26+
}
27+
28+
public void Dispose()
29+
{
30+
Components.Clear();
31+
InternalCache[Type].Enqueue((IList)Components);
32+
}
33+
}
34+
35+
private static readonly Dictionary<Type, Queue<IList>> InternalCache = new Dictionary<Type, Queue<IList>>();
36+
37+
public static IComponentsCache<T> GetComponentsWithCache<T>(this GameObject gameObject, bool withChildren = true)
38+
where T : Component
39+
{
40+
if(gameObject == null)
41+
{
42+
throw new ArgumentNullException(nameof(gameObject));
43+
}
44+
45+
var type = typeof(T);
46+
47+
List<T> cache;
48+
if(!InternalCache.TryGetValue(type, out var cacheQueue))
49+
{
50+
InternalCache.Add(type, cacheQueue = new Queue<IList>());
51+
}
52+
53+
if(cacheQueue.Count == 0)
54+
{
55+
cache = new List<T>(100);
56+
}
57+
else
58+
{
59+
cache = (List<T>)cacheQueue.Dequeue();
60+
cache.Clear();
61+
}
62+
63+
if(withChildren)
64+
{
65+
gameObject.GetComponentsInChildren(cache);
66+
}
67+
else
68+
{
69+
gameObject.GetComponents(cache);
70+
}
71+
72+
return new ComponentsCache<T>(cache);
73+
}
74+
}
75+
}

UnityWeld/Binding/Buffer.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

UnityWeld/Binding/CollectionBinding.cs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ protected override Template CloneTemplate(Template template)
210210
{
211211
if(_pool.TryGetValue(template.ViewModelTypeName, out var pool) && pool.Count > 0)
212212
{
213-
return pool.Dequeue();
213+
return pool.Dequeue();
214214
}
215215

216-
return base.CloneTemplate(template);
216+
return NewTemplate(template);
217217
}
218218

219219
protected override void OnTemplateDestroy(Template template)
@@ -223,9 +223,6 @@ protected override void OnTemplateDestroy(Template template)
223223

224224
private void PutTemplateToPool(Template template)
225225
{
226-
template.gameObject.SetActive(false);
227-
template.SetBindings(false);
228-
229226
if(!_pool.TryGetValue(template.ViewModelTypeName, out var pool))
230227
{
231228
_pool.Add(template.ViewModelTypeName, pool = new Queue<Template>());
@@ -234,19 +231,31 @@ private void PutTemplateToPool(Template template)
234231
pool.Enqueue(template);
235232
}
236233

234+
private Template NewTemplate(Template prefab)
235+
{
236+
var template = Instantiate(prefab, Container);
237+
238+
template.gameObject.SetActive(false);
239+
template.SetBindings(false);
240+
241+
using(var cache = template.gameObject.GetComponentsWithCache<CollectionBinding>())
242+
{
243+
foreach(var binding in cache.Components)
244+
{
245+
binding.WarmUpTemplates();
246+
}
247+
}
248+
249+
return template;
250+
}
251+
237252
public void WarmUpTemplates()
238253
{
239-
foreach(var template in AvailableTemplates.Values)
254+
foreach(var templatePrefab in AvailableTemplates.Values)
240255
{
241256
for(var i = 0; i < TemplateInitialPoolCount; i++)
242257
{
243-
var clone = Instantiate(template, Container);
244-
PutTemplateToPool(clone);
245-
246-
foreach(var collectionBinding in BindingHelpers.IterateComponents<CollectionBinding>(clone.gameObject))
247-
{
248-
collectionBinding.WarmUpTemplates();
249-
}
258+
PutTemplateToPool(NewTemplate(templatePrefab));
250259
}
251260
}
252261
}

UnityWeld/Binding/Internal/PropertyFinder.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,22 @@ public static class PropertyFinder
2626
/// </summary>
2727
public static IEnumerable<BindableMember<PropertyInfo>> GetBindableProperties(GameObject gameObject) //todo: Maybe move this to the TypeResolver.
2828
{
29-
Assert.IsNotNull(gameObject);
30-
31-
var buffer = Buffer.Components;
32-
gameObject.GetComponents<Component>(buffer);
33-
return buffer
34-
.SelectMany(component =>
35-
{
36-
var type = component.GetType();
37-
return type
38-
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
39-
.Select(p => new BindableMember<PropertyInfo>(p, type));
40-
})
41-
.Where(prop => prop.Member.GetSetMethod(false) != null
42-
&& prop.Member.GetGetMethod(false) != null
43-
&& !hiddenTypes.Contains(prop.ViewModelType)
44-
&& !prop.Member.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any()
45-
);
29+
using(var cache = gameObject.GetComponentsWithCache<Component>())
30+
{
31+
return cache.Components
32+
.SelectMany(component =>
33+
{
34+
var type = component.GetType();
35+
return type
36+
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
37+
.Select(p => new BindableMember<PropertyInfo>(p, type));
38+
})
39+
.Where(prop => prop.Member.GetSetMethod(false) != null
40+
&& prop.Member.GetGetMethod(false) != null
41+
&& !hiddenTypes.Contains(prop.ViewModelType)
42+
&& !prop.Member.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any()
43+
);
44+
}
4645
}
4746
}
4847
}

0 commit comments

Comments
 (0)