How do I trigger one block of code whenever any of a set of SignalProducers change? In other words, how do I get rid of my current redundant code:
property1.producer.startWithValues { (value) in
// do stuff with property1.value and property2.value
}
property2.producer.startWithValues { (value) in
// do the same stuff with property1.value and property2.value
}
You can use combineLatest to create a new property that contains both values:
let prop = property1.combineLatest(with: property2)
prop.producer.startWithValues { (val1, val2) in
// do stuff here
}
If either value changes, the block will be triggered.
You can save the block of code as a variable, then you would simply assign that variable to property1.producer.startWithValues.
Related
Is it possible to do something like the following? aka, initialize a variable inside an if statement condition?
Reasoning:
I have a network call that will fetch data, and I'd like to avoid the following options:
Calling it unless the first condition is false.
Calling it twice, once to fetch the data to check the conditional & once to use the data inside the condition
Having to nest if statements
So initializing the variable inside the conditional block seems like the cleanest solution.
if (condition1) {
// Do something
} else if ( (String foo = await getBar()) == "not bar"){
// Do something with foo
} else {
// Fallback condition
}
One option would be to declare the variable before the condition like so:
String foo; // Declare variable here
if (condition1) {
// Do something
} else if ((foo = await getBar()) == "not bar") {
// Do something with foo
} else {
// Fallback condition
}
I noticed over and over again that if i did something like:
#property int x = 1;
...code...
set("x", 2);
print(x);
it will show it as 1. The reason was that it doesnt necessarily execute this immediately. So if i ever set a property I have always made it a point to never use it through the rest of the function. I always believed that set was just called at the end of the current execution.
When dealing with functions a similar approach happens.
It will be assigned but outside the scope of the function. So i would try something like observing it and awaiting for a change in state.
#property Function myFunc = null;
#reflectable
_myFunc(_) => true;
attached(){
set("myFunc", _myFunc);
print("is myFunc null: ${myFunc == null}");
}
will return True.
So I then would also try:
#Observe("myFunc")
functionObservation(_)=>print("Function Called");
but this would not fire.
My desired end state is that when i pass myFunc into another polymer element and try to do stuff with it on that class' attached, as such:
#property Function execFunc = null;
attached(){
if(execFunc != null)
execFunc();
}
so when passing it into another component there are issues.
I am not 100% sure if this is a life cycle issue, or a set error but it seems that when i do it in attached, OR define a future:
attached(){
new Future((){
execFunc()
});
}
It will still not seem to be assigned.
you should rewrite your props as setters and getters and use the setter for notification :
int _myProp;
#reflectable
int get myProp => _myProp;
set myProp(v) {
_myProp = v;
notifyPath('myProp');
}
Or use something like autonotify to automatically get properties notified for you.
This way you are guaranteed that this code always stamp 5 in the console:
myProp=5
print("${myProp}");
regardless the possible async polymer setter behavior.
I'd like to implement method chaining in my swift code, likely to Alamofire methods. For example, if I have to use my function like below
getListForID(12).Success {
// Success block
}. Failure {
// Failure block
}
How would I create the function getListForID?
To expand on the great points #dasblinkenlight and #Sulthan have made – here's a small example of how you could achieve your request function to take a success and failure closure, in the convenient syntax that you want.
First, you'll have to define a new class to represent the 'result handler'. This is what your success and failure functions will pass around, allowing you to add multiple trailing closures to make up your completion block logic. You'll want it to look something like this:
class ResultHandler {
typealias SuccessClosure = RequestHandler.Output->Void
typealias FailureClosure = Void->Void
// the success and failure callback arrays
private var _successes = [SuccessClosure]()
private var _failures = [FailureClosure]()
/// Invoke all the stored callbacks with a given callback result
func invokeCallbacks(result:RequestHandler.Result) {
switch result {
case .Success(let output): _successes.forEach{$0(output)}
case .Failure: _failures.forEach{$0()}
}
}
// remove all callbacks – could call this from within invokeCallbacks
// depending on the re-usability of the class
func removeAllCallbacks() {
_successes.removeAll()
_failures.removeAll()
}
/// appends a new success callback to the result handler's successes array
func success(closure:SuccessClosure) -> Self {
_successes.append(closure)
return self
}
/// appends a new failure callback to the result handler's failures array
func failure(closure:FailureClosure) -> Self {
_failures.append(closure)
return self
}
}
This will allow you to define multiple success or failure closures to be executed on completion. If you don't actually need the capacity for multiple closures, then you can simplify the class down by stripping out the arrays – and just keeping track of the last added success and failure completion blocks instead.
Now all you have to do is define a function that generates a new ResultHandler instance and then does a given asynchronous request, with the invokeCallbacks method being invoked upon completion:
func doRequest(input:Input) -> ResultHandler {
let resultHandler = ResultHandler()
doSomethingAsynchronous(resultHandler.invokeCallbacks)
return resultHandler
}
Now you can call it like this:
doRequest(input).success {result in
print("success, with:", result)
}.failure {
print("fail :(")
}
The only thing to note is your doSomethingAsynchronous function will have to dispatch its completion block back to the main thread, to ensure thread safety.
Full project (with added example on usage): https://github.com/hamishknight/Callback-Closure-Chaining
In order to understand what is going on, it would help to rewrite your code without the "convenience" syntax, which lets you omit parentheses when a closure is the last parameter of a function:
getListForID(12)
.Success( { /* Success block */ } )
.Failure( { /* Failure block */ } )
This makes the structure of the code behind this API more clear:
The return value of getListForID must be an object
The object must have two function called Success and Failure*
Both Success and Failure need to take a single parameter of closure type
Both Success and Failure need to return self
* The object could have only Success function, and return a different object with a single Failure function, but then you wouldn't be able to re-order the Success and Failure handlers, or drop Success handler altogether.
The code is on DartPad if you need a complete example (see the while loop towards the end.)
I have a loop,
Place place = places[0];
while (places.isNotEmpty) {
// Get a list of places within distance (we can travel to)
List reachables = place.getReachables();
// Get the closest reachable place
Place closest = place.getClosest(reachables);
// Remove the current place (ultimately should terminate the loop)
places.remove(place);
// Iterate
place = closest;
}
But it's not removing place on the second-to-last line. i.e., the length of the places list remains the same, making it an infinite loop. What's wrong?
This could be because the object in the list has a different hashCode from the object you are trying to remove.
Try using this code instead, to find the correct object by comparing the objects properties, before removing it:
var item = list.firstWhere((x) => x.property1== myObj.property1 && x.property2== myObj.property2, orElse: () => null);
list.remove(item);
Another option is to override the == operator and hashCode in your class.
class Class1 {
#override
bool operator==(other) {
if(other is! Class1) {
return false;
}
return property1 == (other as Class1).property1;
}
int _hashCode;
#override
int get hashCode {
if(_hashCode == null) {
_hashCode = property1.hashCode
}
return _hashCode;
}
}
I have faced the very same issue. Unfortunately I haven't found the root cause, but in the same situation I replaced
places.remove[place]
with
places.removeWhere(p => p.hachCode == place.hashCode)
as a workaround. One more approach was helpful too:
// Get the place from your set:
final place = places.first;
// Replace the place in the set:
places.add(place);
// Remove the place from the set:
places.remove(place);
Most likely place is not in the list for some reason. It's hard to debug without knowing the exact data used, the problem doesn't reproduce with the three-place sample you have in the linked DartPad.
Try figuring out which element is causing the problem. For example you can
try adding an if (!places.contains(place)) print("!!! $place not in $places"); before the remove, or something similar that detects the state when the problem occurs.
This way you can remove object from dynamic list
List data = [
{
"name":"stack"
},
{
"name":"overflow"
}
];
data.removeWhere((item) => item["name"]=="stack");
print(data);
Output
[{name: overflow}]
Use the plugin Equatable
class Place extends Equatable {
...
}
https://pub.dev/packages/equatable
I was having the same issue. I did something like this using removeWhere.
myList.removeWhere((item) => item.id == yourItemId.id)
I need help with something very interesting. I try to remove child from parent or fro stage dinamicly but not just removeChild and I want to destroy entire object. Here is very simple example what I want to do.
public function TestProject()
{
holder = new Sprite();
this.addChild(holder);
object1 = new Sprite();
object1.name = "object1";
object1.graphics.beginFill(0x6daeff);
object1.graphics.drawRect(0,0,100,100);
holder.addChild(object1);
stage.addEventListener(MouseEvent.CLICK,onClick);
}
protected function onClick(event:MouseEvent):void
{
var tmp:DisplayObject = holder.removeChild(object1);
tmp = null;
// holder.removeChild(object1) = null; this give me error.
}
//with this code object1 was removed from stage but object1 is not null. When I debug
object1 = flash.display.Sprite ; etc.
I want to remove child and at the same this child to be null.
Any ideas...
To clean up memory you have to destroy all references to your object. In this case:
protected function onClick(event:MouseEvent):void
{
if (holder.contains(object1))
holder.removeChild(object1);
object1 = null;
}
or
protected function onClick(event:MouseEvent):void
{
if (object1.parent)
object1.parent.removeChild(object1);
object1 = null;
}
Note: When you'd applied null to local variable tmp you didn't affect the object1 instance variable.
Thanks for your answer but the point is in this example I write just one object. I Ask when I have 100 object for example. Something like this:
for(var i:int=0;i<holder.numOfChilder;i++)
{
holder.getChildAt(i).addEventListener(Event.MouseEvent,onObjectClick)
}
function onObjectClick():void
{
holder.removeChild(event.currentTarget as DisplayObject) = null;
}
child object are dynamic created and I want dynamic removed
To cleanup object that was created dynamically and to which you have no reference variable, just remove all event listers to it, to make it eligible for GC:
function onObjectClick(event:MouseEvent):void
{
var target:DisplayObject = (event.currentTarget as DisplayObject);
target.removeEventListener(MouseEvent.CLICK, onObjectClick);
holder.removeChild(target);
}
Note: there is no need to set null to you local variable cause it will die automatically since method run will be finished
Note2: u can set useWeakReference=true during adding your listener
to allow your listener being garbage-collected automatically.