Swift Task Continuation Misuse: Leaked Its Continuation - for Delegate

SWIFT TASK CONTINUATION MISUSE: leaked its continuation

Your guard is capturing a case and not calling the continuation. You need to call the continuation (e.g. continuation.resume(...)) from all branches so that it is not leaked.

This early return is causing the issue

guard case let .failure(error) = response.result else { return }

In your example you would need to decide how to handle response.data being nil and response.result being success and then update your guard to invoke continuation.resume(...) appropriately.

Swift: using combination of Combine and async/await results in Fatal error: SWIFT TASK CONTINUATION MISUSE tried to resume its continuation

A continuation must be resumed exactly once. You are retaining the continuation in the sink closure, and you have a constant publisher value, so the second time you hit the button, a new sink operation is created and the publisher is now sending its results to two continuations. You need to make the sink operation happen once only by unsubscribing it when it's done, or by nullifying a local reference to the continuation in the sink (untested example below):

let autocompletedComponents = await withCheckedContinuation { continuation in
var oneShot = Optional(continuation)
publisher
.sink {
oneShot?.resume(returning: $0)
oneShot = nil
}
.store(in: &cancellables)
}

However, apart from learning purposes it's not clear what benefits you're adding by mixing Combine and structured concurrency in this example. Given that the nature of the local search completer is to deliver a continuously updating set of values as the user types, Combine seems like a better fit here. You could wrap the delegate calls with a continuation but you'd have the same problem, you must resume the continuation once and only once which probably means creating brand new delegates for each request.

Pending Task in Swift

You don't need to use Task to do this. You can use withCheckedThrowingContinuation to convert the method f into an async throws method. Then when you call it, a child task of the current task is automatically created and you can await it directly.

class A: NSObject, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var continuation: CheckedContinuation<CLLocation, Error>?
func f() async throws -> CLLocation {
try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
locationManager.delegate = self
locationManager.requestLocation()
}
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
continuation?.resume(returning: locations[0])
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
continuation?.resume(throwing: error)
}
}

Your B.f method can also be rewritten as an async method (I don't know what cauterize does):

class B {
let a = A()

func f() async {
do {
print(try await a.f())
} catch {
print(error)
}
}
}

let b = B()

_runAsyncMain { // so that we have an async context to await tasks
await b.f()
}

Side note: if you actually run this, you will get an error printed from the catch block, probably because location manager needs permission :)

Async/Await function without a return | Swift 5.5

This is what worked the best:

try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation<Void, Error>) in

Composing Task.async_stream vs. Continuation passing

If both functions are IO bound, then there shouldn't be any problem with your first example:

enum
|> Task.async_stream(Mod1, :func1, [])
|> Task.async_stream(Mod2, :func2, [])

If you did want to collapse the two calls, I wouldn't use a continuation style, just pipeline them in a lambda passed to Task.async_stream/3:

enum
|> Task.async_stream(fn x -> x |> Mod1.func1() |> M2.func2() end)

Alternatively, you might consider using Flow:

enum 
|> Flow.from_enumerable()
|> Flow.map(&Mod1.func1/1)
|> Flow.map(&Mod2.func2/1)
|> Flow.run()

Async in Task ContinueWith behavior?

The code below is equivalent to your example, with variables explicitly declared, so that it's easier to see what's going on:

Task task = Task.Run(() => { });

Task<Task> continuation1 = task.ContinueWith(async prev =>
{
Console.WriteLine("Continue with 1 start");
await Task.Delay(1000);
Console.WriteLine("Continue with 1 end");
});

Task continuation2 = continuation1.ContinueWith(prev =>
{
Console.WriteLine("Continue with 2 start");
});

await continuation2;
Console.WriteLine($"task.IsCompleted: {task.IsCompleted}");
Console.WriteLine($"continuation1.IsCompleted: {continuation1.IsCompleted}");
Console.WriteLine($"continuation2.IsCompleted: {continuation2.IsCompleted}");

Console.WriteLine($"continuation1.Unwrap().IsCompleted:" +
$" {continuation1.Unwrap().IsCompleted}");

await await continuation1;

Output:

Continue with 1 start

Continue with 2 start

task.IsCompleted: True

continuation1.IsCompleted: True

continuation2.IsCompleted: True

continuation1.Unwrap().IsCompleted: False

Continue with 1 end

The tricky part is the variable continuation1, that is of type Task<Task>. The ContinueWith method does not unwrap automatically the Task<Task> return values like Task.Run does, so you end up with these nested tasks-of-tasks. The outer Task's job is just to create the inner Task. When the inner Task has been created (not completed!), then the outer Task has been completed. This is why the continuation2 is completed before the inner Task of the continuation1.

There is a built-in extension method Unwrap that makes it easy to unwrap a Task<Task>. An unwrapped Task is completed when both the outer and the inner tasks are completed. An alternative way to unwrap a Task<Task> is to use the await operator twice: await await.

Castle Windsor equivalent of StructureMap ObjectFactory.With ().GetInstance ()

You can register an instance as the implementation of a given component like this:

container.Register(Component
.For<ISomeDependency>()
.Instance(someDependencyInstance));

This means that everytime you resolve anything and ISomeDependency is part of the resolved object graph, the someDependencyInstance instance will be used.

It that what you want, or did I misunderstand the question?


Based on additional information, here's a new attempt at answering the question.

You should be able to use container hierarchies for this. If a Windsor container can't resolve a type, it'll ask its parent. This means that you can create a child container that contains only the override and then ask that container to resolve the type for you.

Here's an example:

var container = new WindsorContainer();
container.Register(Component
.For<ISomeDependency>()
.ImplementedBy<SomeDependency>());
container.Register(Component
.For<IService>()
.ImplementedBy<Service>());

var childContainer = new WindsorContainer();
childContainer.Register(Component
.For<ISomeDependency>()
.ImplementedBy<SomeOtherDependency>());

childContainer.Parent = container;

var service = childContainer.Resolve<IService>();

The resolved service will contain an instance of SomeOtherDependency and not SomeDependency.

Notice how childContainer only overrides the registration of ISomeDependency. All other registrations are used from the parent.



Related Topics



Leave a reply



Submit